From b6856af9d82d9b7f3fe546e9575ace2e903eab38 Mon Sep 17 00:00:00 2001 From: Jehan Date: Sun, 26 Nov 2023 21:37:52 +0100 Subject: [PATCH] app: GimpGradient now uses GeglColor. I still see some limitations in GimpGradient, and in particular, they are still always stored as RGB in GGR files. It would be nice if we could store the actual color format. This way, if someone chooses a gradient stop as Lab or CMYK color, that's what the gradient file would keep track of. But also even storing the space of a color (instead of storing/loading always in sRGB, even though this may still work fine as we store unbounded double values). This might warrant for a v2 of GGR file format. This commit also fixes loading of SVG gradient which was apparently broken regarding hexadecimal color parsing. Finally I improve gegl_color_set_alpha() by adding an alpha channel when the initial format had none. --- app/actions/gradient-editor-actions.c | 78 ++-- app/actions/gradient-editor-commands.c | 85 ++--- app/core/gimpgradient-load.c | 72 ++-- app/core/gimpgradient-save.c | 60 +-- app/core/gimpgradient.c | 416 +++++++++++++-------- app/core/gimpgradient.h | 98 +++-- app/core/gimppalette-import.c | 12 +- app/operations/gimpoperationgradient.c | 27 +- app/paint/gimppaintbrush.c | 7 +- app/paint/gimppaintoptions.c | 12 +- app/paint/gimppaintoptions.h | 2 +- app/paint/gimpsmudge.c | 28 +- app/pdb/gradient-cmds.c | 170 +++------ app/tools/gimpgradienttool-editor.c | 65 ++-- app/widgets/gimpgradienteditor.c | 116 +++--- app/widgets/gimpgradienteditor.h | 2 +- app/widgets/gimpgradientselect.c | 11 +- app/widgets/gimpviewrenderer.c | 8 + app/widgets/gimpviewrenderer.h | 2 + app/widgets/gimpviewrenderergradient.c | 34 +- libgimp/gimpgradient_pdb.c | 78 ++-- libgimp/gimpgradient_pdb.h | 18 +- libgimpcolor/gimpcolor-parse.c | 481 +++++++++++++++++++++++++ libgimpcolor/gimpcolor.c | 64 ++++ libgimpcolor/gimpcolor.def | 1 + libgimpcolor/gimpcolor.h | 11 +- libgimpcolor/meson.build | 1 + pdb/groups/gradient.pdb | 93 ++--- 28 files changed, 1330 insertions(+), 722 deletions(-) create mode 100644 libgimpcolor/gimpcolor-parse.c diff --git a/app/actions/gradient-editor-actions.c b/app/actions/gradient-editor-actions.c index f47cfc2786..49cf68031d 100644 --- a/app/actions/gradient-editor-actions.c +++ b/app/actions/gradient-editor-actions.c @@ -461,22 +461,22 @@ void gradient_editor_actions_update (GimpActionGroup *group, gpointer data) { - GimpGradientEditor *editor = GIMP_GRADIENT_EDITOR (data); - GimpDataEditor *data_editor = GIMP_DATA_EDITOR (data); + GimpGradientEditor *editor = GIMP_GRADIENT_EDITOR (data); + GimpDataEditor *data_editor = GIMP_DATA_EDITOR (data); GimpGradient *gradient; - gboolean editable = FALSE; + gboolean editable = FALSE; GeglColor *color; - GimpRGB left_color; - GimpRGB right_color; - GimpRGB left_seg_color; - GimpRGB right_seg_color; - gboolean blending_equal = TRUE; - gboolean coloring_equal = TRUE; - gboolean left_editable = TRUE; - gboolean right_editable = TRUE; - gboolean selection = FALSE; - gboolean delete = FALSE; - gboolean edit_active = FALSE; + GeglColor *left_color = NULL; + GeglColor *right_color = NULL; + GeglColor *left_seg_color = NULL; + GeglColor *right_seg_color = NULL; + gboolean blending_equal = TRUE; + gboolean coloring_equal = TRUE; + gboolean left_editable = TRUE; + gboolean right_editable = TRUE; + gboolean selection = FALSE; + gboolean delete = FALSE; + gboolean edit_active = FALSE; gradient = GIMP_GRADIENT (data_editor->data); @@ -491,35 +491,31 @@ gradient_editor_actions_update (GimpActionGroup *group, if (data_editor->data_editable) editable = TRUE; - gimp_gradient_segment_get_left_flat_color (gradient, - data_editor->context, - editor->control_sel_l, - &left_color); + left_color = gimp_gradient_segment_get_left_flat_color (gradient, + data_editor->context, + editor->control_sel_l); if (editor->control_sel_l->prev) left_seg = editor->control_sel_l->prev; else left_seg = gimp_gradient_segment_get_last (editor->control_sel_l); - gimp_gradient_segment_get_right_flat_color (gradient, - data_editor->context, - left_seg, - &left_seg_color); + left_seg_color = gimp_gradient_segment_get_right_flat_color (gradient, + data_editor->context, + left_seg); - gimp_gradient_segment_get_right_flat_color (gradient, - data_editor->context, - editor->control_sel_r, - &right_color); + right_color = gimp_gradient_segment_get_right_flat_color (gradient, + data_editor->context, + editor->control_sel_r); if (editor->control_sel_r->next) right_seg = editor->control_sel_r->next; else right_seg = gimp_gradient_segment_get_first (editor->control_sel_r); - gimp_gradient_segment_get_left_flat_color (gradient, - data_editor->context, - right_seg, - &right_seg_color); + right_seg_color = gimp_gradient_segment_get_left_flat_color (gradient, + data_editor->context, + right_seg); left_editable = (editor->control_sel_l->left_color_type == GIMP_GRADIENT_COLOR_FIXED); @@ -610,12 +606,9 @@ gradient_editor_actions_update (GimpActionGroup *group, if (gradient) { - gegl_color_set_pixel (color, babl_format ("R'G'B'A double"), &left_color); - SET_COLOR ("gradient-editor-left-color", color, FALSE); - gegl_color_set_pixel (color, babl_format ("R'G'B'A double"), &left_seg_color); - SET_COLOR ("gradient-editor-load-left-left-neighbor", color, FALSE); - gegl_color_set_pixel (color, babl_format ("R'G'B'A double"), &right_color); - SET_COLOR ("gradient-editor-load-left-right-endpoint", color, FALSE); + SET_COLOR ("gradient-editor-left-color", left_color, FALSE); + SET_COLOR ("gradient-editor-load-left-left-neighbor", left_seg_color, FALSE); + SET_COLOR ("gradient-editor-load-left-right-endpoint", right_color, FALSE); } SET_SENSITIVE ("gradient-editor-load-left-fg", left_editable); @@ -724,12 +717,9 @@ gradient_editor_actions_update (GimpActionGroup *group, if (gradient) { - gegl_color_set_pixel (color, babl_format ("R'G'B'A double"), &right_color); - SET_COLOR ("gradient-editor-right-color", color, FALSE); - gegl_color_set_pixel (color, babl_format ("R'G'B'A double"), &right_seg_color); - SET_COLOR ("gradient-editor-load-right-right-neighbor", color, FALSE); - gegl_color_set_pixel (color, babl_format ("R'G'B'A double"), &left_color); - SET_COLOR ("gradient-editor-load-right-left-endpoint", color, FALSE); + SET_COLOR ("gradient-editor-right-color", right_color, FALSE); + SET_COLOR ("gradient-editor-load-right-right-neighbor", right_seg_color, FALSE); + SET_COLOR ("gradient-editor-load-right-left-endpoint", left_color, FALSE); } SET_SENSITIVE ("gradient-editor-load-right-fg", right_editable); @@ -939,4 +929,8 @@ gradient_editor_actions_update (GimpActionGroup *group, #undef SET_VISIBLE g_object_unref (color); + g_clear_object (&left_color); + g_clear_object (&right_color); + g_clear_object (&left_seg_color); + g_clear_object (&right_seg_color); } diff --git a/app/actions/gradient-editor-commands.c b/app/actions/gradient-editor-commands.c index cf794af698..c9d6a2d7d0 100644 --- a/app/actions/gradient-editor-commands.c +++ b/app/actions/gradient-editor-commands.c @@ -80,18 +80,21 @@ gradient_editor_left_color_type_cmd_callback (GimpAction *action, color_type != gimp_gradient_segment_get_left_color_type (gradient, left)) { - GimpRGB color; - - gimp_gradient_segment_get_left_flat_color (gradient, - GIMP_DATA_EDITOR (editor)->context, - left, &color); - gimp_data_freeze (GIMP_DATA (gradient)); gimp_gradient_segment_set_left_color_type (gradient, left, color_type); if (color_type == GIMP_GRADIENT_COLOR_FIXED) - gimp_gradient_segment_set_left_color (gradient, left, &color); + { + GeglColor *color; + + color = gimp_gradient_segment_get_left_flat_color (gradient, + GIMP_DATA_EDITOR (editor)->context, + left); + + gimp_gradient_segment_set_left_color (gradient, left, color); + g_object_unref (color); + } gimp_data_thaw (GIMP_DATA (gradient)); } @@ -108,8 +111,7 @@ gradient_editor_load_left_cmd_callback (GimpAction *action, GimpGradientSegment *left; GimpGradientSegment *right; GimpGradientSegment *seg; - GeglColor *color = NULL; - GimpRGB rgb; + GeglColor *color; GimpGradientColor color_type = GIMP_GRADIENT_COLOR_FIXED; gint index = g_variant_get_int32 (value); @@ -123,12 +125,12 @@ gradient_editor_load_left_cmd_callback (GimpAction *action, else seg = gimp_gradient_segment_get_last (left); - rgb = seg->right_color; + color = seg->right_color; color_type = seg->right_color_type; break; case GRADIENT_EDITOR_COLOR_OTHER_ENDPOINT: - rgb = right->right_color; + color = right->right_color; color_type = right->right_color_type; break; @@ -141,19 +143,14 @@ gradient_editor_load_left_cmd_callback (GimpAction *action, break; default: /* Load a color */ - rgb = editor->saved_colors[index - GRADIENT_EDITOR_COLOR_FIRST_CUSTOM]; + color = editor->saved_colors[index - GRADIENT_EDITOR_COLOR_FIRST_CUSTOM]; break; } - if (color != NULL) - gegl_color_get_rgba_with_space (color, &rgb.r, &rgb.g, &rgb.b, &rgb.a, NULL); - gimp_data_freeze (GIMP_DATA (gradient)); - gimp_gradient_segment_range_blend (gradient, left, right, - &rgb, - &right->right_color, - TRUE, TRUE); + gimp_gradient_segment_range_blend (gradient, left, right, color, + right->right_color, TRUE, TRUE); gimp_gradient_segment_set_left_color_type (gradient, left, color_type); gimp_data_thaw (GIMP_DATA (gradient)); @@ -171,8 +168,8 @@ gradient_editor_save_left_cmd_callback (GimpAction *action, gimp_gradient_editor_get_selection (editor, &gradient, &left, NULL); - gimp_gradient_segment_get_left_color (gradient, left, - &editor->saved_colors[index]); + g_clear_object (&editor->saved_colors[index]); + editor->saved_colors[index] = gegl_color_duplicate (gimp_gradient_segment_get_left_color (gradient, left)); } void @@ -204,18 +201,20 @@ gradient_editor_right_color_type_cmd_callback (GimpAction *action, color_type != gimp_gradient_segment_get_right_color_type (gradient, right)) { - GimpRGB color; - - gimp_gradient_segment_get_right_flat_color (gradient, - GIMP_DATA_EDITOR (editor)->context, - right, &color); - gimp_data_freeze (GIMP_DATA (gradient)); gimp_gradient_segment_set_right_color_type (gradient, right, color_type); if (color_type == GIMP_GRADIENT_COLOR_FIXED) - gimp_gradient_segment_set_right_color (gradient, right, &color); + { + GeglColor *color; + + color = gimp_gradient_segment_get_right_flat_color (gradient, GIMP_DATA_EDITOR (editor)->context, + right); + + gimp_gradient_segment_set_right_color (gradient, right, color); + g_object_unref (color); + } gimp_data_thaw (GIMP_DATA (gradient)); } @@ -232,8 +231,7 @@ gradient_editor_load_right_cmd_callback (GimpAction *action, GimpGradientSegment *left; GimpGradientSegment *right; GimpGradientSegment *seg; - GeglColor *color = NULL; - GimpRGB rgb; + GeglColor *color; GimpGradientColor color_type = GIMP_GRADIENT_COLOR_FIXED; gint index = g_variant_get_int32 (value); @@ -247,12 +245,12 @@ gradient_editor_load_right_cmd_callback (GimpAction *action, else seg = gimp_gradient_segment_get_first (right); - rgb = seg->left_color; + color = seg->left_color; color_type = seg->left_color_type; break; case GRADIENT_EDITOR_COLOR_OTHER_ENDPOINT: - rgb = left->left_color; + color = left->left_color; color_type = left->left_color_type; break; @@ -265,19 +263,14 @@ gradient_editor_load_right_cmd_callback (GimpAction *action, break; default: /* Load a color */ - rgb = editor->saved_colors[index - GRADIENT_EDITOR_COLOR_FIRST_CUSTOM]; + color = editor->saved_colors[index - GRADIENT_EDITOR_COLOR_FIRST_CUSTOM]; break; } - if (color != NULL) - gegl_color_get_rgba_with_space (color, &rgb.r, &rgb.g, &rgb.b, &rgb.a, NULL); - gimp_data_freeze (GIMP_DATA (gradient)); - gimp_gradient_segment_range_blend (gradient, left, right, - &left->left_color, - &rgb, - TRUE, TRUE); + gimp_gradient_segment_range_blend (gradient, left, right, left->left_color, + color, TRUE, TRUE); gimp_gradient_segment_set_right_color_type (gradient, left, color_type); gimp_data_thaw (GIMP_DATA (gradient)); @@ -295,8 +288,8 @@ gradient_editor_save_right_cmd_callback (GimpAction *action, gimp_gradient_editor_get_selection (editor, &gradient, NULL, &right); - gimp_gradient_segment_get_right_color (gradient, right, - &editor->saved_colors[index]); + g_clear_object (&editor->saved_colors[index]); + editor->saved_colors[index] = gegl_color_duplicate (gimp_gradient_segment_get_right_color (gradient, right)); } void @@ -637,8 +630,8 @@ gradient_editor_blend_color_cmd_callback (GimpAction *action, gimp_gradient_editor_get_selection (editor, &gradient, &left, &right); gimp_gradient_segment_range_blend (gradient, left, right, - &left->left_color, - &right->right_color, + left->left_color, + right->right_color, TRUE, FALSE); } @@ -655,8 +648,8 @@ gradient_editor_blend_opacity_cmd_callback (GimpAction *action, gimp_gradient_editor_get_selection (editor, &gradient, &left, &right); gimp_gradient_segment_range_blend (gradient, left, right, - &left->left_color, - &right->right_color, + left->left_color, + right->right_color, FALSE, TRUE); } diff --git a/app/core/gimpgradient-load.c b/app/core/gimpgradient-load.c index 1abe49498e..aaaa63bf3f 100644 --- a/app/core/gimpgradient-load.c +++ b/app/core/gimpgradient-load.c @@ -133,6 +133,8 @@ gimp_gradient_load (GimpContext *context, gint type; gint left_color_type; gint right_color_type; + gdouble left_rgba[4]; + gdouble right_rgba[4]; seg = gimp_gradient_segment_new (); @@ -150,19 +152,19 @@ gimp_gradient_load (GimpContext *context, if (! line) goto failed; - if (! gimp_ascii_strtod (line, &end, &seg->left) || - ! gimp_ascii_strtod (end, &end, &seg->middle) || - ! gimp_ascii_strtod (end, &end, &seg->right) || + if (! gimp_ascii_strtod (line, &end, &seg->left) || + ! gimp_ascii_strtod (end, &end, &seg->middle) || + ! gimp_ascii_strtod (end, &end, &seg->right) || - ! gimp_ascii_strtod (end, &end, &seg->left_color.r) || - ! gimp_ascii_strtod (end, &end, &seg->left_color.g) || - ! gimp_ascii_strtod (end, &end, &seg->left_color.b) || - ! gimp_ascii_strtod (end, &end, &seg->left_color.a) || + ! gimp_ascii_strtod (end, &end, &left_rgba[0]) || + ! gimp_ascii_strtod (end, &end, &left_rgba[1]) || + ! gimp_ascii_strtod (end, &end, &left_rgba[2]) || + ! gimp_ascii_strtod (end, &end, &left_rgba[3]) || - ! gimp_ascii_strtod (end, &end, &seg->right_color.r) || - ! gimp_ascii_strtod (end, &end, &seg->right_color.g) || - ! gimp_ascii_strtod (end, &end, &seg->right_color.b) || - ! gimp_ascii_strtod (end, &end, &seg->right_color.a)) + ! gimp_ascii_strtod (end, &end, &right_rgba[0]) || + ! gimp_ascii_strtod (end, &end, &right_rgba[1]) || + ! gimp_ascii_strtod (end, &end, &right_rgba[2]) || + ! gimp_ascii_strtod (end, &end, &right_rgba[3])) { g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ, _("Corrupt segment %d."), i); @@ -170,6 +172,9 @@ gimp_gradient_load (GimpContext *context, goto failed; } + gegl_color_set_pixel (seg->left_color, babl_format ("R'G'B'A double"), left_rgba); + gegl_color_set_pixel (seg->right_color, babl_format ("R'G'B'A double"), right_rgba); + switch (sscanf (end, "%d %d %d %d", &type, &color, &left_color_type, &right_color_type)) @@ -276,7 +281,8 @@ typedef struct typedef struct { gdouble offset; - GimpRGB color; + GeglColor *color; + gdouble opacity; } SvgStop; @@ -414,7 +420,12 @@ svg_parser_end_element (GMarkupParseContext *context, parser->gradient->segments = svg_parser_gradient_segments (parser->stops); for (list = parser->stops; list; list = list->next) - g_slice_free (SvgStop, list->data); + { + SvgStop *stop = list->data; + + g_clear_object (&stop->color); + g_slice_free (SvgStop, stop); + } g_list_free (parser->stops); parser->stops = NULL; @@ -443,8 +454,10 @@ svg_parser_gradient_segments (GList *stops) segment = gimp_gradient_segment_new (); - segment->left_color = stop->color; - segment->right_color = stop->color; + g_clear_object (&segment->left_color); + segment->left_color = gegl_color_duplicate (stop->color); + g_clear_object (&segment->right_color); + segment->right_color = gegl_color_duplicate (stop->color); /* the list of offsets is sorted from largest to smallest */ for (list = g_list_next (stops); list; list = g_list_next (list)) @@ -460,17 +473,22 @@ svg_parser_gradient_segments (GList *stops) next->prev = segment; segment->right = stop->offset; - segment->right_color = stop->color; + g_clear_object (&segment->right_color); + segment->right_color = gegl_color_duplicate (stop->color); stop = list->data; - segment->left_color = stop->color; + g_clear_object (&segment->left_color); + segment->left_color = gegl_color_duplicate (stop->color); } segment->middle = (segment->left + segment->right) / 2.0; if (stop->offset > 0.0) - segment->right_color = stop->color; + { + g_clear_object (&segment->right_color); + segment->right_color = gegl_color_duplicate (stop->color); + } /* FIXME: remove empty segments here or add a GimpGradient API to do that */ @@ -485,14 +503,15 @@ svg_parse_gradient_stop_style_prop (SvgStop *stop, { if (strcmp (name, "stop-color") == 0) { - gimp_rgb_parse_css (&stop->color, value, -1); + g_clear_object (&stop->color); + stop->color = gimp_color_parse_css (value, -1); } else if (strcmp (name, "stop-opacity") == 0) { gdouble opacity = g_ascii_strtod (value, NULL); if (errno != ERANGE) - gimp_rgb_set_alpha (&stop->color, CLAMP (opacity, 0.0, 1.0)); + stop->opacity = CLAMP (opacity, 0.0, 1.0); } } @@ -522,7 +541,7 @@ svg_parse_gradient_stop_style (SvgStop *stop, name = g_strndup (style, sep - style); sep++; - value = g_strndup (sep, end - sep - (*end == ';' ? 1 : 0)); + value = g_strndup (sep, end - sep); svg_parse_gradient_stop_style_prop (stop, name, value); @@ -543,7 +562,8 @@ svg_parse_gradient_stop (const gchar **names, { SvgStop *stop = g_slice_new0 (SvgStop); - gimp_rgb_set_alpha (&stop->color, 1.0); + stop->color = NULL; + stop->opacity = 1.0; while (*names && *values) { @@ -571,5 +591,13 @@ svg_parse_gradient_stop (const gchar **names, values++; } + if (! stop->color) + /* Default stop color is black: + * https://svgwg.org/svg2-draft/pservers.html#GradientStops + */ + stop->color = gegl_color_new ("black"); + + gimp_color_set_alpha (stop->color, stop->opacity); + return stop; } diff --git a/app/core/gimpgradient-save.c b/app/core/gimpgradient-save.c index deca2d27c6..829dd06809 100644 --- a/app/core/gimpgradient-save.c +++ b/app/core/gimpgradient-save.c @@ -70,19 +70,24 @@ gimp_gradient_save (GimpData *data, for (seg = gradient->segments; seg; seg = seg->next) { - gchar buf[11][G_ASCII_DTOSTR_BUF_SIZE]; + gchar buf[11][G_ASCII_DTOSTR_BUF_SIZE]; + gdouble rgba[4]; g_ascii_dtostr (buf[0], G_ASCII_DTOSTR_BUF_SIZE, seg->left); g_ascii_dtostr (buf[1], G_ASCII_DTOSTR_BUF_SIZE, seg->middle); g_ascii_dtostr (buf[2], G_ASCII_DTOSTR_BUF_SIZE, seg->right); - g_ascii_dtostr (buf[3], G_ASCII_DTOSTR_BUF_SIZE, seg->left_color.r); - g_ascii_dtostr (buf[4], G_ASCII_DTOSTR_BUF_SIZE, seg->left_color.g); - g_ascii_dtostr (buf[5], G_ASCII_DTOSTR_BUF_SIZE, seg->left_color.b); - g_ascii_dtostr (buf[6], G_ASCII_DTOSTR_BUF_SIZE, seg->left_color.a); - g_ascii_dtostr (buf[7], G_ASCII_DTOSTR_BUF_SIZE, seg->right_color.r); - g_ascii_dtostr (buf[8], G_ASCII_DTOSTR_BUF_SIZE, seg->right_color.g); - g_ascii_dtostr (buf[9], G_ASCII_DTOSTR_BUF_SIZE, seg->right_color.b); - g_ascii_dtostr (buf[10], G_ASCII_DTOSTR_BUF_SIZE, seg->right_color.a); + + gegl_color_get_pixel (seg->left_color, babl_format ("R'G'B'A double"), rgba); + g_ascii_dtostr (buf[3], G_ASCII_DTOSTR_BUF_SIZE, rgba[0]); + g_ascii_dtostr (buf[4], G_ASCII_DTOSTR_BUF_SIZE, rgba[1]); + g_ascii_dtostr (buf[5], G_ASCII_DTOSTR_BUF_SIZE, rgba[2]); + g_ascii_dtostr (buf[6], G_ASCII_DTOSTR_BUF_SIZE, rgba[3]); + + gegl_color_get_pixel (seg->right_color, babl_format ("R'G'B'A double"), rgba); + g_ascii_dtostr (buf[7], G_ASCII_DTOSTR_BUF_SIZE, rgba[0]); + g_ascii_dtostr (buf[8], G_ASCII_DTOSTR_BUF_SIZE, rgba[1]); + g_ascii_dtostr (buf[9], G_ASCII_DTOSTR_BUF_SIZE, rgba[2]); + g_ascii_dtostr (buf[10], G_ASCII_DTOSTR_BUF_SIZE, rgba[3]); g_string_append_printf (string, "%s %s %s %s %s %s %s %s %s %s %s %d %d %d %d\n", @@ -136,17 +141,17 @@ gimp_gradient_save_pov (GimpGradient *gradient, for (seg = gradient->segments; seg; seg = seg->next) { + gdouble left_rgba[4]; + gdouble right_rgba[4]; + /* Left */ g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, seg->left); - g_ascii_dtostr (color_buf[0], G_ASCII_DTOSTR_BUF_SIZE, - seg->left_color.r); - g_ascii_dtostr (color_buf[1], G_ASCII_DTOSTR_BUF_SIZE, - seg->left_color.g); - g_ascii_dtostr (color_buf[2], G_ASCII_DTOSTR_BUF_SIZE, - seg->left_color.b); - g_ascii_dtostr (color_buf[3], G_ASCII_DTOSTR_BUF_SIZE, - 1.0 - seg->left_color.a); + gegl_color_get_pixel (seg->left_color, babl_format ("R'G'B'A double"), left_rgba); + g_ascii_dtostr (color_buf[0], G_ASCII_DTOSTR_BUF_SIZE, left_rgba[0]); + g_ascii_dtostr (color_buf[1], G_ASCII_DTOSTR_BUF_SIZE, left_rgba[1]); + g_ascii_dtostr (color_buf[2], G_ASCII_DTOSTR_BUF_SIZE, left_rgba[2]); + g_ascii_dtostr (color_buf[3], G_ASCII_DTOSTR_BUF_SIZE, 1.0 - left_rgba[3]); g_string_append_printf (string, "\t[%s color rgbt <%s, %s, %s, %s>]\n", @@ -157,14 +162,15 @@ gimp_gradient_save_pov (GimpGradient *gradient, /* Middle */ g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, seg->middle); + gegl_color_get_pixel (seg->right_color, babl_format ("R'G'B'A double"), right_rgba); g_ascii_dtostr (color_buf[0], G_ASCII_DTOSTR_BUF_SIZE, - (seg->left_color.r + seg->right_color.r) / 2.0); + (left_rgba[0] + right_rgba[0]) / 2.0); g_ascii_dtostr (color_buf[1], G_ASCII_DTOSTR_BUF_SIZE, - (seg->left_color.g + seg->right_color.g) / 2.0); + (left_rgba[1] + right_rgba[1]) / 2.0); g_ascii_dtostr (color_buf[2], G_ASCII_DTOSTR_BUF_SIZE, - (seg->left_color.b + seg->right_color.b) / 2.0); + (left_rgba[2] + right_rgba[2]) / 2.0); g_ascii_dtostr (color_buf[3], G_ASCII_DTOSTR_BUF_SIZE, - 1.0 - (seg->left_color.a + seg->right_color.a) / 2.0); + 1.0 - (left_rgba[3] + right_rgba[3]) / 2.0); g_string_append_printf (string, "\t[%s color rgbt <%s, %s, %s, %s>]\n", @@ -175,14 +181,10 @@ gimp_gradient_save_pov (GimpGradient *gradient, /* Right */ g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, seg->right); - g_ascii_dtostr (color_buf[0], G_ASCII_DTOSTR_BUF_SIZE, - seg->right_color.r); - g_ascii_dtostr (color_buf[1], G_ASCII_DTOSTR_BUF_SIZE, - seg->right_color.g); - g_ascii_dtostr (color_buf[2], G_ASCII_DTOSTR_BUF_SIZE, - seg->right_color.b); - g_ascii_dtostr (color_buf[3], G_ASCII_DTOSTR_BUF_SIZE, - 1.0 - seg->right_color.a); + g_ascii_dtostr (color_buf[0], G_ASCII_DTOSTR_BUF_SIZE, right_rgba[0]); + g_ascii_dtostr (color_buf[1], G_ASCII_DTOSTR_BUF_SIZE, right_rgba[1]); + g_ascii_dtostr (color_buf[2], G_ASCII_DTOSTR_BUF_SIZE, right_rgba[2]); + g_ascii_dtostr (color_buf[3], G_ASCII_DTOSTR_BUF_SIZE, 1.0 - right_rgba[3]); g_string_append_printf (string, "\t[%s color rgbt <%s, %s, %s, %s>]\n", diff --git a/app/core/gimpgradient.c b/app/core/gimpgradient.c index a7851dd6d1..44c2bc0f26 100644 --- a/app/core/gimpgradient.c +++ b/app/core/gimpgradient.c @@ -74,10 +74,9 @@ static inline GimpGradientSegment * gimp_gradient_get_segment_at_internal (GimpGradient *gradient, GimpGradientSegment *seg, gdouble pos); -static void gimp_gradient_get_flat_color (GimpContext *context, - const GimpRGB *color, - GimpGradientColor color_type, - GimpRGB *flat_color); +static GeglColor * gimp_gradient_get_flat_color (GimpContext *context, + GeglColor *color, + GimpGradientColor color_type); static inline gdouble gimp_gradient_calc_linear_factor (gdouble middle, @@ -224,7 +223,6 @@ gimp_gradient_get_new_preview (GimpViewable *viewable, guchar *row; gint x, y; gdouble dx, cur_x; - GimpRGB color; dx = 1.0 / (width - 1); cur_x = 0.0; @@ -234,17 +232,19 @@ gimp_gradient_get_new_preview (GimpViewable *viewable, for (x = 0; x < width; x++) { + GeglColor *color = NULL; + seg = gimp_gradient_get_color_at (gradient, context, seg, cur_x, FALSE, GIMP_GRADIENT_BLEND_RGB_PERCEPTUAL, &color); - *p++ = ROUND (color.r * 255.0); - *p++ = ROUND (color.g * 255.0); - *p++ = ROUND (color.b * 255.0); - *p++ = ROUND (color.a * 255.0); + gegl_color_get_pixel (color, babl_format ("R'G'B'A u8"), p); + p += 4; cur_x += dx; + + g_object_unref (color); } temp_buf = gimp_temp_buf_new (width, height, babl_format ("R'G'B'A u8")); @@ -285,6 +285,8 @@ gimp_gradient_copy (GimpData *data, cur->prev = prev; cur->next = NULL; + cur->left_color = gegl_color_duplicate (orig->left_color); + cur->right_color = gegl_color_duplicate (orig->right_color); if (prev) prev->next = cur; @@ -341,9 +343,13 @@ gimp_gradient_get_checksum (GimpTagged *tagged) { GChecksum *checksum = g_checksum_new (G_CHECKSUM_MD5); GimpGradientSegment *segment = gradient->segments; + guchar data[40]; while (segment) { + const Babl *format; + gsize length; + g_checksum_update (checksum, (const guchar *) &segment->left, sizeof (segment->left)); @@ -356,15 +362,25 @@ gimp_gradient_get_checksum (GimpTagged *tagged) g_checksum_update (checksum, (const guchar *) &segment->left_color_type, sizeof (segment->left_color_type)); - g_checksum_update (checksum, - (const guchar *) &segment->left_color, - sizeof (segment->left_color)); + + format = gegl_color_get_format (segment->left_color); + gegl_color_get_pixel (segment->left_color, format, data); + length = babl_format_get_bytes_per_pixel (format); + g_checksum_update (checksum, data, (gssize) length); + g_checksum_update (checksum, (const guchar *) babl_get_name (format), + strlen (babl_get_name (format))); + g_checksum_update (checksum, (const guchar *) &segment->right_color_type, sizeof (segment->right_color_type)); - g_checksum_update (checksum, - (const guchar *) &segment->right_color, - sizeof (segment->right_color)); + + format = gegl_color_get_format (segment->right_color); + gegl_color_get_pixel (segment->right_color, format, data); + length = babl_format_get_bytes_per_pixel (format); + g_checksum_update (checksum, data, (gssize) length); + g_checksum_update (checksum, (const guchar *) babl_get_name (format), + strlen (babl_get_name (format))); + g_checksum_update (checksum, (const guchar *) &segment->type, sizeof (segment->type)); @@ -435,7 +451,7 @@ gimp_gradient_get_extension (GimpData *data) * @pos: position in the gradient (between 0.0 and 1.0) * @reverse: when %TRUE, use the reversed gradient * @blend_color_space: color space to use for blending RGB segments - * @color: returns the color + * @color: returns a newly allocated color * * If you are iterating over an gradient, you should pass the the * return value from the last call for @seg. @@ -443,24 +459,27 @@ gimp_gradient_get_extension (GimpData *data) * Returns: the gradient segment the color is from **/ GimpGradientSegment * -gimp_gradient_get_color_at (GimpGradient *gradient, - GimpContext *context, - GimpGradientSegment *seg, - gdouble pos, - gboolean reverse, - GimpGradientBlendColorSpace blend_color_space, - GimpRGB *color) +gimp_gradient_get_color_at (GimpGradient *gradient, + GimpContext *context, + GimpGradientSegment *seg, + gdouble pos, + gboolean reverse, + GimpGradientBlendColorSpace blend_color_space, + GeglColor **color) { - gdouble factor = 0.0; - gdouble seg_len; - gdouble middle; - GimpRGB left_color; - GimpRGB right_color; - GimpRGB rgb; + gdouble factor = 0.0; + gdouble seg_len; + gdouble middle; + GeglColor *left_color; + GeglColor *right_color; + gdouble left_alpha; + gdouble right_alpha; /* type-check disabled to improve speed */ /* g_return_val_if_fail (GIMP_IS_GRADIENT (gradient), NULL); */ - g_return_val_if_fail (color != NULL, NULL); + g_return_val_if_fail (color != NULL && *color == NULL, NULL); + + *color = gegl_color_new (NULL); pos = CLAMP (pos, 0.0, 1.0); @@ -517,98 +536,99 @@ gimp_gradient_get_color_at (GimpGradient *gradient, if (context) { - gimp_gradient_segment_get_left_flat_color (gradient, - context, seg, &left_color); - - gimp_gradient_segment_get_right_flat_color (gradient, - context, seg, &right_color); + left_color = gimp_gradient_segment_get_left_flat_color (gradient, context, seg); + right_color = gimp_gradient_segment_get_right_flat_color (gradient, context, seg); } else { - left_color = seg->left_color; - right_color = seg->right_color; + left_color = g_object_ref (seg->left_color); + right_color = g_object_ref (seg->right_color); } /* Calculate color components */ if (seg->color == GIMP_GRADIENT_SEGMENT_RGB) { + gdouble left_components[3]; + gdouble right_components[3]; + gdouble ret_components[3]; + switch (blend_color_space) { case GIMP_GRADIENT_BLEND_CIE_LAB: - babl_process (fish_srgb_to_cie_lab, - &left_color, &left_color, 1); - babl_process (fish_srgb_to_cie_lab, - &right_color, &right_color, 1); + gegl_color_get_pixel (left_color, babl_format ("CIE Lab double"), left_components); + gegl_color_get_pixel (right_color, babl_format ("CIE Lab double"), right_components); break; case GIMP_GRADIENT_BLEND_RGB_LINEAR: - babl_process (fish_srgb_to_linear_rgb, - &left_color, &left_color, 1); - babl_process (fish_srgb_to_linear_rgb, - &right_color, &right_color, 1); + gegl_color_get_pixel (left_color, babl_format ("RGB double"), left_components); + gegl_color_get_pixel (right_color, babl_format ("RGB double"), right_components); case GIMP_GRADIENT_BLEND_RGB_PERCEPTUAL: + /* TODO: shouldn't this format use the color space of the target + * image? Will it change computation? */ + gegl_color_get_pixel (left_color, babl_format ("R'G'B' double"), left_components); + gegl_color_get_pixel (right_color, babl_format ("R'G'B' double"), right_components); break; } - rgb.r = left_color.r + (right_color.r - left_color.r) * factor; - rgb.g = left_color.g + (right_color.g - left_color.g) * factor; - rgb.b = left_color.b + (right_color.b - left_color.b) * factor; + ret_components[0] = left_components[0] + (right_components[0] - left_components[0]) * factor; + ret_components[1] = left_components[1] + (right_components[1] - left_components[1]) * factor; + ret_components[2] = left_components[2] + (right_components[2] - left_components[2]) * factor; switch (blend_color_space) { case GIMP_GRADIENT_BLEND_CIE_LAB: - babl_process (fish_cie_lab_to_srgb, - &rgb, &rgb, 1); + gegl_color_set_pixel (*color, babl_format ("CIE Lab double"), ret_components); break; case GIMP_GRADIENT_BLEND_RGB_LINEAR: - babl_process (fish_linear_rgb_to_srgb, - &rgb, &rgb, 1); + gegl_color_set_pixel (*color, babl_format ("RGB double"), ret_components); + break; case GIMP_GRADIENT_BLEND_RGB_PERCEPTUAL: + gegl_color_set_pixel (*color, babl_format ("R'G'B' double"), ret_components); break; } } else { - GimpHSV left_hsv; - GimpHSV right_hsv; + gdouble left_hsv[3]; + gdouble right_hsv[3]; - gimp_rgb_to_hsv (&left_color, &left_hsv); - gimp_rgb_to_hsv (&right_color, &right_hsv); + gegl_color_get_pixel (left_color, babl_format ("HSV double"), left_hsv); + gegl_color_get_pixel (right_color, babl_format ("HSV double"), right_hsv); - left_hsv.s = left_hsv.s + (right_hsv.s - left_hsv.s) * factor; - left_hsv.v = left_hsv.v + (right_hsv.v - left_hsv.v) * factor; + left_hsv[1] = left_hsv[1] + (right_hsv[1] - left_hsv[1]) * factor; + left_hsv[2] = left_hsv[2] + (right_hsv[2] - left_hsv[2]) * factor; switch (seg->color) { case GIMP_GRADIENT_SEGMENT_HSV_CCW: - if (left_hsv.h < right_hsv.h) + if (left_hsv[0] < right_hsv[0]) { - left_hsv.h += (right_hsv.h - left_hsv.h) * factor; + left_hsv[0] += (right_hsv[0] - left_hsv[0]) * factor; } else { - left_hsv.h += (1.0 - (left_hsv.h - right_hsv.h)) * factor; + left_hsv[0] += (1.0 - (left_hsv[0] - right_hsv[0])) * factor; - if (left_hsv.h > 1.0) - left_hsv.h -= 1.0; + if (left_hsv[0] > 1.0) + left_hsv[0] -= 1.0; } break; case GIMP_GRADIENT_SEGMENT_HSV_CW: - if (right_hsv.h < left_hsv.h) + if (right_hsv[0] < left_hsv[0]) { - left_hsv.h -= (left_hsv.h - right_hsv.h) * factor; + left_hsv[0] -= (left_hsv[0] - right_hsv[0]) * factor; } else { - left_hsv.h -= (1.0 - (right_hsv.h - left_hsv.h)) * factor; + left_hsv[0] -= (1.0 - (right_hsv[0] - left_hsv[0])) * factor; - if (left_hsv.h < 0.0) - left_hsv.h += 1.0; + if (left_hsv[0] < 0.0) + left_hsv[0] += 1.0; } break; @@ -618,14 +638,17 @@ gimp_gradient_get_color_at (GimpGradient *gradient, break; } - gimp_hsv_to_rgb (&left_hsv, &rgb); + gegl_color_set_pixel (*color, babl_format ("HSV double"), left_hsv); } /* Calculate alpha */ - rgb.a = left_color.a + (right_color.a - left_color.a) * factor; + gegl_color_get_rgba (left_color, NULL, NULL, NULL, &left_alpha); + gegl_color_get_rgba (right_color, NULL, NULL, NULL, &right_alpha); + gimp_color_set_alpha (*color, left_alpha + (right_alpha - left_alpha) * factor); - *color = rgb; + g_object_unref (left_color); + g_object_unref (right_color); return seg; } @@ -663,7 +686,7 @@ gimp_gradient_split_at (GimpGradient *gradient, GimpGradientSegment **newl, GimpGradientSegment **newr) { - GimpRGB color; + GeglColor *color = NULL; GimpGradientSegment *newseg; g_return_if_fail (GIMP_IS_GRADIENT (gradient)); @@ -703,11 +726,15 @@ gimp_gradient_split_at (GimpGradient *gradient, /* Set colors of both segments */ + g_clear_object (&newseg->right_color); + g_clear_object (&newseg->left_color); + newseg->right_color_type = seg->right_color_type; newseg->right_color = seg->right_color; seg->right_color_type = newseg->left_color_type = GIMP_GRADIENT_COLOR_FIXED; - seg->right_color = newseg->left_color = color; + seg->right_color = color; + newseg->left_color = gegl_color_duplicate (color); /* Set parameters of new segment */ @@ -736,15 +763,17 @@ gimp_gradient_flatten (GimpGradient *gradient, for (seg = flat->segments; seg; seg = seg->next) { - gimp_gradient_segment_get_left_flat_color (gradient, - context, seg, - &seg->left_color); + GeglColor *color; + + color = gimp_gradient_segment_get_left_flat_color (gradient, context, seg); + g_clear_object (&seg->left_color); + seg->left_color = color; seg->left_color_type = GIMP_GRADIENT_COLOR_FIXED; - gimp_gradient_segment_get_right_flat_color (gradient, - context, seg, - &seg->right_color); + color = gimp_gradient_segment_get_right_flat_color (gradient, context, seg); + g_clear_object (&seg->right_color); + seg->right_color = color; seg->right_color_type = GIMP_GRADIENT_COLOR_FIXED; } @@ -767,10 +796,10 @@ gimp_gradient_segment_new (void) seg->right = 1.0; seg->left_color_type = GIMP_GRADIENT_COLOR_FIXED; - gimp_rgba_set (&seg->left_color, 0.0, 0.0, 0.0, 1.0); + seg->left_color = gegl_color_new ("black"); seg->right_color_type = GIMP_GRADIENT_COLOR_FIXED; - gimp_rgba_set (&seg->right_color, 1.0, 1.0, 1.0, 1.0); + seg->right_color = gegl_color_new ("white"); seg->type = GIMP_GRADIENT_SEGMENT_LINEAR; seg->color = GIMP_GRADIENT_SEGMENT_RGB; @@ -786,15 +815,29 @@ gimp_gradient_segment_free (GimpGradientSegment *seg) { g_return_if_fail (seg != NULL); + g_clear_object (&seg->right_color); + g_clear_object (&seg->left_color); g_slice_free (GimpGradientSegment, seg); } void gimp_gradient_segments_free (GimpGradientSegment *seg) { + GimpGradientSegment *current = seg; + GimpGradientSegment *next; + g_return_if_fail (seg != NULL); - g_slice_free_chain (GimpGradientSegment, seg, next); + if (seg->prev) + seg->prev->next = NULL; + + do + { + next = current->next; + gimp_gradient_segment_free (current); + current = next; + } + while (next); } GimpGradientSegment * @@ -891,6 +934,8 @@ gimp_gradient_segment_split_uniform (GimpGradient *gradient, for (i = 0; i < parts; i++) { + GeglColor *color = NULL; + seg = gimp_gradient_segment_new (); if (i == 0) @@ -905,10 +950,16 @@ gimp_gradient_segment_split_uniform (GimpGradient *gradient, gimp_gradient_get_color_at (gradient, context, lseg, seg->left, FALSE, blend_color_space, - &seg->left_color); + &color); + g_clear_object (&seg->left_color); + seg->left_color = color; + + color = NULL; gimp_gradient_get_color_at (gradient, context, lseg, seg->right, FALSE, blend_color_space, - &seg->right_color); + &color); + g_clear_object (&seg->right_color); + seg->right_color = color; seg->type = lseg->type; seg->color = lseg->color; @@ -925,10 +976,12 @@ gimp_gradient_segment_split_uniform (GimpGradient *gradient, /* Fix edges */ tmp->left_color_type = lseg->left_color_type; - tmp->left_color = lseg->left_color; + g_clear_object (&tmp->left_color); + tmp->left_color = gegl_color_duplicate (lseg->left_color); seg->right_color_type = lseg->right_color_type; - seg->right_color = lseg->right_color; + g_clear_object (&seg->right_color); + seg->right_color = gegl_color_duplicate (lseg->right_color); tmp->left = lseg->left; seg->right = lseg->right; /* To squish accumulative error */ @@ -956,61 +1009,57 @@ gimp_gradient_segment_split_uniform (GimpGradient *gradient, gimp_data_thaw (GIMP_DATA (gradient)); } -void +GeglColor * gimp_gradient_segment_get_left_color (GimpGradient *gradient, - GimpGradientSegment *seg, - GimpRGB *color) + GimpGradientSegment *seg) { - g_return_if_fail (GIMP_IS_GRADIENT (gradient)); - g_return_if_fail (seg != NULL); - g_return_if_fail (color != NULL); + g_return_val_if_fail (GIMP_IS_GRADIENT (gradient), NULL); + g_return_val_if_fail (seg != NULL, NULL); - *color = seg->left_color; + return seg->left_color; } void gimp_gradient_segment_set_left_color (GimpGradient *gradient, GimpGradientSegment *seg, - const GimpRGB *color) + GeglColor *color) { g_return_if_fail (GIMP_IS_GRADIENT (gradient)); g_return_if_fail (seg != NULL); - g_return_if_fail (color != NULL); + g_return_if_fail (GEGL_IS_COLOR (color)); gimp_data_freeze (GIMP_DATA (gradient)); gimp_gradient_segment_range_blend (gradient, seg, seg, - color, &seg->right_color, + color, seg->right_color, TRUE, TRUE); gimp_data_thaw (GIMP_DATA (gradient)); } -void +GeglColor * gimp_gradient_segment_get_right_color (GimpGradient *gradient, - GimpGradientSegment *seg, - GimpRGB *color) + GimpGradientSegment *seg) { - g_return_if_fail (GIMP_IS_GRADIENT (gradient)); - g_return_if_fail (seg != NULL); - g_return_if_fail (color != NULL); + g_return_val_if_fail (GIMP_IS_GRADIENT (gradient), NULL); + g_return_val_if_fail (seg != NULL, NULL); - *color = seg->right_color; + return seg->right_color; } void gimp_gradient_segment_set_right_color (GimpGradient *gradient, GimpGradientSegment *seg, - const GimpRGB *color) + GeglColor *color) { g_return_if_fail (GIMP_IS_GRADIENT (gradient)); g_return_if_fail (seg != NULL); - g_return_if_fail (color != NULL); + g_return_if_fail (GEGL_IS_COLOR (color)); gimp_data_freeze (GIMP_DATA (gradient)); gimp_gradient_segment_range_blend (gradient, seg, seg, - &seg->left_color, color, + seg->left_color, color, TRUE, TRUE); gimp_data_thaw (GIMP_DATA (gradient)); @@ -1066,34 +1115,28 @@ gimp_gradient_segment_set_right_color_type (GimpGradient *gradient, gimp_data_thaw (GIMP_DATA (gradient)); } -void +GeglColor * gimp_gradient_segment_get_left_flat_color (GimpGradient *gradient, GimpContext *context, - GimpGradientSegment *seg, - GimpRGB *color) + GimpGradientSegment *seg) { - g_return_if_fail (GIMP_IS_GRADIENT (gradient)); - g_return_if_fail (seg != NULL); - g_return_if_fail (color != NULL); + g_return_val_if_fail (GIMP_IS_GRADIENT (gradient), NULL); + g_return_val_if_fail (seg != NULL, NULL); - gimp_gradient_get_flat_color (context, - &seg->left_color, seg->left_color_type, - color); + return gimp_gradient_get_flat_color (context, + seg->left_color, seg->left_color_type); } -void +GeglColor * gimp_gradient_segment_get_right_flat_color (GimpGradient *gradient, GimpContext *context, - GimpGradientSegment *seg, - GimpRGB *color) + GimpGradientSegment *seg) { - g_return_if_fail (GIMP_IS_GRADIENT (gradient)); - g_return_if_fail (seg != NULL); - g_return_if_fail (color != NULL); + g_return_val_if_fail (GIMP_IS_GRADIENT (gradient), NULL); + g_return_val_if_fail (seg != NULL, NULL); - gimp_gradient_get_flat_color (context, - &seg->right_color, seg->right_color_type, - color); + return gimp_gradient_get_flat_color (context, + seg->right_color, seg->right_color_type); } gdouble @@ -1320,15 +1363,26 @@ void gimp_gradient_segment_range_blend (GimpGradient *gradient, GimpGradientSegment *lseg, GimpGradientSegment *rseg, - const GimpRGB *rgb1, - const GimpRGB *rgb2, + GeglColor *color1, + GeglColor *color2, gboolean blend_colors, gboolean blend_opacity) { - GimpRGB d; gdouble left, len; GimpGradientSegment *seg; GimpGradientSegment *aseg; + gdouble red1; + gdouble green1; + gdouble blue1; + gdouble alpha1; + gdouble red2; + gdouble green2; + gdouble blue2; + gdouble alpha2; + gdouble dred; + gdouble dgreen; + gdouble dblue; + gdouble dalpha; g_return_if_fail (GIMP_IS_GRADIENT (gradient)); g_return_if_fail (lseg != NULL); @@ -1338,10 +1392,15 @@ gimp_gradient_segment_range_blend (GimpGradient *gradient, if (! rseg) rseg = gimp_gradient_segment_get_last (lseg); - d.r = rgb2->r - rgb1->r; - d.g = rgb2->g - rgb1->g; - d.b = rgb2->b - rgb1->b; - d.a = rgb2->a - rgb1->a; + /* TODO: currently doing this computation with sRGB value, because that's what + * was done historically. Is it right though? + */ + gegl_color_get_rgba_with_space (color1, &red1, &green1, &blue1, &alpha1, NULL); + gegl_color_get_rgba_with_space (color2, &red2, &green2, &blue2, &alpha2, NULL); + dred = red2 - red1; + dgreen = green2 - green1; + dblue = blue2 - blue1; + dalpha = alpha2 - alpha1; left = lseg->left; len = rseg->right - left; @@ -1350,21 +1409,50 @@ gimp_gradient_segment_range_blend (GimpGradient *gradient, do { + gdouble seg_left_red; + gdouble seg_left_green; + gdouble seg_left_blue; + gdouble seg_left_alpha; + gdouble seg_right_red; + gdouble seg_right_green; + gdouble seg_right_blue; + gdouble seg_right_alpha; + if (blend_colors) { - seg->left_color.r = rgb1->r + (seg->left - left) / len * d.r; - seg->left_color.g = rgb1->g + (seg->left - left) / len * d.g; - seg->left_color.b = rgb1->b + (seg->left - left) / len * d.b; + seg_left_red = red1 + (seg->left - left) / len * dred; + seg_left_green = green1 + (seg->left - left) / len * dgreen; + seg_left_blue = blue1 + (seg->left - left) / len * dblue; - seg->right_color.r = rgb1->r + (seg->right - left) / len * d.r; - seg->right_color.g = rgb1->g + (seg->right - left) / len * d.g; - seg->right_color.b = rgb1->b + (seg->right - left) / len * d.b; + seg_right_red = red1 + (seg->right - left) / len * dred; + seg_right_green = green1 + (seg->right - left) / len * dgreen; + seg_right_blue = blue1 + (seg->right - left) / len * dblue; + } + else if (blend_opacity) + { + gegl_color_get_rgba_with_space (seg->left_color, &seg_left_red, &seg_left_green, + &seg_left_blue, NULL, NULL); + gegl_color_get_rgba_with_space (seg->right_color, &seg_right_red, &seg_right_green, + &seg_right_blue, NULL, NULL); } if (blend_opacity) { - seg->left_color.a = rgb1->a + (seg->left - left) / len * d.a; - seg->right_color.a = rgb1->a + (seg->right - left) / len * d.a; + seg_left_alpha = alpha1 + (seg->left - left) / len * dalpha; + seg_right_alpha = alpha1 + (seg->right - left) / len * dalpha; + } + else if (blend_colors) + { + gegl_color_get_rgba_with_space (seg->left_color, NULL, NULL, NULL, &seg_left_alpha, NULL); + gegl_color_get_rgba_with_space (seg->right_color, NULL, NULL, NULL, &seg_right_alpha, NULL); + } + + if (blend_colors || blend_opacity) + { + gegl_color_set_rgba_with_space (seg->left_color, seg_left_red, seg_left_green, + seg_left_blue, seg_left_alpha, NULL); + gegl_color_set_rgba_with_space (seg->right_color, seg_right_red, seg_right_green, + seg_right_blue, seg_right_alpha, NULL); } aseg = seg; @@ -1465,16 +1553,21 @@ gimp_gradient_segment_range_flip (GimpGradient *gradient, tmp = seg; /* Remember first segment */ } else - seg->left = left + right - oseg->right; + { + seg->left = left + right - oseg->right; + } seg->middle = left + right - oseg->middle; seg->right = left + right - oseg->left; + g_clear_object (&seg->left_color); + g_clear_object (&seg->right_color); + seg->left_color_type = oseg->right_color_type; - seg->left_color = oseg->right_color; + seg->left_color = gegl_color_duplicate (oseg->right_color); seg->right_color_type = oseg->left_color_type; - seg->right_color = oseg->left_color; + seg->right_color = gegl_color_duplicate (oseg->left_color); switch (oseg->type) { @@ -1629,11 +1722,14 @@ gimp_gradient_segment_range_replicate (GimpGradient *gradient, seg->middle = new_left + factor * (oseg->middle - sel_left); seg->right = new_left + factor * (oseg->right - sel_left); + g_clear_object (&seg->left_color); + g_clear_object (&seg->right_color); + seg->left_color_type = oseg->left_color_type; - seg->left_color = oseg->left_color; + seg->left_color = gegl_color_duplicate (oseg->left_color); seg->right_color_type = oseg->right_color_type; - seg->right_color = oseg->right_color; + seg->right_color = gegl_color_duplicate (oseg->right_color); seg->type = oseg->type; seg->color = oseg->color; @@ -1908,11 +2004,15 @@ gimp_gradient_segment_range_merge (GimpGradient *gradient, gimp_data_freeze (GIMP_DATA (gradient)); + if (start_seg == end_seg) + goto out; + /* Copy the end segment's right position and color to the start segment */ start_seg->right = end_seg->right; start_seg->right_color_type = end_seg->right_color_type; - start_seg->right_color = end_seg->right_color; + g_clear_object (&start_seg->right_color); + start_seg->right_color = gegl_color_duplicate (end_seg->right_color); /* Center the start segment's midpoint */ @@ -1948,6 +2048,8 @@ gimp_gradient_segment_range_merge (GimpGradient *gradient, seg = prev; } +out: + if (final_start_seg) *final_start_seg = start_seg; if (final_end_seg) @@ -2193,41 +2295,37 @@ gimp_gradient_get_segment_at_internal (GimpGradient *gradient, return seg; } -static void +static GeglColor * gimp_gradient_get_flat_color (GimpContext *context, - const GimpRGB *rgb, - GimpGradientColor color_type, - GimpRGB *flat_color) + GeglColor *color, + GimpGradientColor color_type) { - GeglColor *color = NULL; + GeglColor *flat_color = NULL; switch (color_type) { case GIMP_GRADIENT_COLOR_FIXED: - *flat_color = *rgb; + flat_color = gegl_color_duplicate (color); break; case GIMP_GRADIENT_COLOR_FOREGROUND: case GIMP_GRADIENT_COLOR_FOREGROUND_TRANSPARENT: - color = gegl_color_duplicate (gimp_context_get_foreground (context)); + flat_color = gegl_color_duplicate (gimp_context_get_foreground (context)); if (color_type == GIMP_GRADIENT_COLOR_FOREGROUND_TRANSPARENT) - gimp_color_set_alpha (color, 0.0); + gimp_color_set_alpha (flat_color, 0.0); break; case GIMP_GRADIENT_COLOR_BACKGROUND: case GIMP_GRADIENT_COLOR_BACKGROUND_TRANSPARENT: - color = gegl_color_duplicate (gimp_context_get_background (context)); + flat_color = gegl_color_duplicate (gimp_context_get_background (context)); if (color_type == GIMP_GRADIENT_COLOR_BACKGROUND_TRANSPARENT) - gimp_color_set_alpha (color, 0.0); + gimp_color_set_alpha (flat_color, 0.0); break; } - if (color != NULL) - gegl_color_get_rgba_with_space (color, &flat_color->r, &flat_color->g, &flat_color->b, &flat_color->a, NULL); - - g_clear_object (&color); + return flat_color; } static inline gdouble diff --git a/app/core/gimpgradient.h b/app/core/gimpgradient.h index 8aa817d7e0..ccf919811d 100644 --- a/app/core/gimpgradient.h +++ b/app/core/gimpgradient.h @@ -30,9 +30,9 @@ struct _GimpGradientSegment gdouble left, middle, right; GimpGradientColor left_color_type; - GimpRGB left_color; + GeglColor *left_color; GimpGradientColor right_color_type; - GimpRGB right_color; + GeglColor *right_color; GimpGradientSegmentType type; /* Segment's blending function */ GimpGradientSegmentColor color; /* Segment's coloring type */ @@ -71,22 +71,22 @@ GimpData * gimp_gradient_new (GimpContext *context, const gchar *name); GimpData * gimp_gradient_get_standard (GimpContext *context); -GimpGradientSegment * gimp_gradient_get_color_at (GimpGradient *gradient, - GimpContext *context, - GimpGradientSegment *seg, - gdouble pos, - gboolean reverse, - GimpGradientBlendColorSpace blend_color_space, - GimpRGB *color); -GimpGradientSegment * gimp_gradient_get_segment_at (GimpGradient *grad, - gdouble pos); -void gimp_gradient_split_at (GimpGradient *gradient, - GimpContext *context, - GimpGradientSegment *seg, - gdouble pos, - GimpGradientBlendColorSpace blend_color_space, - GimpGradientSegment **newl, - GimpGradientSegment **newr); +GimpGradientSegment * gimp_gradient_get_color_at (GimpGradient *gradient, + GimpContext *context, + GimpGradientSegment *seg, + gdouble pos, + gboolean reverse, + GimpGradientBlendColorSpace blend_color_space, + GeglColor **color); +GimpGradientSegment * gimp_gradient_get_segment_at (GimpGradient *grad, + gdouble pos); +void gimp_gradient_split_at (GimpGradient *gradient, + GimpContext *context, + GimpGradientSegment *seg, + gdouble pos, + GimpGradientBlendColorSpace blend_color_space, + GimpGradientSegment **newl, + GimpGradientSegment **newr); gboolean gimp_gradient_has_fg_bg_segments (GimpGradient *gradient); GimpGradient * gimp_gradient_flatten (GimpGradient *gradient, @@ -104,37 +104,35 @@ GimpGradientSegment * gimp_gradient_segment_get_nth (GimpGradientSegment *seg, void gimp_gradient_segment_free (GimpGradientSegment *seg); void gimp_gradient_segments_free (GimpGradientSegment *seg); -void gimp_gradient_segment_split_midpoint (GimpGradient *gradient, - GimpContext *context, - GimpGradientSegment *lseg, - GimpGradientBlendColorSpace blend_color_space, - GimpGradientSegment **newl, - GimpGradientSegment **newr); -void gimp_gradient_segment_split_uniform (GimpGradient *gradient, - GimpContext *context, - GimpGradientSegment *lseg, - gint parts, - GimpGradientBlendColorSpace blend_color_space, - GimpGradientSegment **newl, - GimpGradientSegment **newr); +void gimp_gradient_segment_split_midpoint (GimpGradient *gradient, + GimpContext *context, + GimpGradientSegment *lseg, + GimpGradientBlendColorSpace blend_color_space, + GimpGradientSegment **newl, + GimpGradientSegment **newr); +void gimp_gradient_segment_split_uniform (GimpGradient *gradient, + GimpContext *context, + GimpGradientSegment *lseg, + gint parts, + GimpGradientBlendColorSpace blend_color_space, + GimpGradientSegment **newl, + GimpGradientSegment **newr); /* Colors Setting/Getting Routines */ -void gimp_gradient_segment_get_left_color (GimpGradient *gradient, - GimpGradientSegment *seg, - GimpRGB *color); +GeglColor * gimp_gradient_segment_get_left_color (GimpGradient *gradient, + GimpGradientSegment *seg); -void gimp_gradient_segment_set_left_color (GimpGradient *gradient, - GimpGradientSegment *seg, - const GimpRGB *color); +void gimp_gradient_segment_set_left_color (GimpGradient *gradient, + GimpGradientSegment *seg, + GeglColor *color); -void gimp_gradient_segment_get_right_color (GimpGradient *gradient, - GimpGradientSegment *seg, - GimpRGB *color); +GeglColor * gimp_gradient_segment_get_right_color (GimpGradient *gradient, + GimpGradientSegment *seg); -void gimp_gradient_segment_set_right_color (GimpGradient *gradient, - GimpGradientSegment *seg, - const GimpRGB *color); +void gimp_gradient_segment_set_right_color (GimpGradient *gradient, + GimpGradientSegment *seg, + GeglColor *color); GimpGradientColor @@ -157,18 +155,16 @@ gimp_gradient_segment_set_right_color_type (GimpGradient *gradient, GimpGradientColor color_type); -void +GeglColor * gimp_gradient_segment_get_left_flat_color (GimpGradient *gradient, GimpContext *context, - GimpGradientSegment *seg, - GimpRGB *color); + GimpGradientSegment *seg); -void +GeglColor * gimp_gradient_segment_get_right_flat_color (GimpGradient *gradient, GimpContext *context, - GimpGradientSegment *seg, - GimpRGB *color); + GimpGradientSegment *seg); /* Position Setting/Getting Routines */ @@ -216,8 +212,8 @@ void gimp_gradient_segment_range_compress (GimpGradient *gradient, void gimp_gradient_segment_range_blend (GimpGradient *gradient, GimpGradientSegment *lseg, GimpGradientSegment *rseg, - const GimpRGB *rgb1, - const GimpRGB *rgb2, + GeglColor *color1, + GeglColor *color2, gboolean blend_colors, gboolean blend_opacity); diff --git a/app/core/gimppalette-import.c b/app/core/gimppalette-import.c index bb6cff5a18..6c34fe7817 100644 --- a/app/core/gimppalette-import.c +++ b/app/core/gimppalette-import.c @@ -56,7 +56,6 @@ gimp_palette_import_from_gradient (GimpGradient *gradient, GimpPalette *palette; GimpGradientSegment *seg = NULL; gdouble dx, cur_x; - GimpRGB color; gint i; g_return_val_if_fail (GIMP_IS_GRADIENT (gradient), NULL); @@ -70,10 +69,19 @@ gimp_palette_import_from_gradient (GimpGradient *gradient, for (i = 0, cur_x = 0; i < n_colors; i++, cur_x += dx) { + GeglColor *color = NULL; + GimpRGB rgb; + seg = gimp_gradient_get_color_at (gradient, context, seg, cur_x, reverse, blend_color_space, &color); - gimp_palette_add_entry (palette, -1, NULL, &color); + + g_return_val_if_fail (color != NULL, palette); + + gegl_color_get_pixel (color, babl_format ("R'G'B'A double"), &rgb); + gimp_palette_add_entry (palette, -1, NULL, &rgb); + + g_clear_object (&color); } return palette; diff --git a/app/operations/gimpoperationgradient.c b/app/operations/gimpoperationgradient.c index 2dbb74666d..01b1894e72 100644 --- a/app/operations/gimpoperationgradient.c +++ b/app/operations/gimpoperationgradient.c @@ -455,6 +455,9 @@ gimp_operation_gradient_set_property (GObject *object, { GimpGradient *gradient = g_value_get_object (value); + if (gradient) + g_object_ref (gradient); + g_clear_object (&self->gradient); if (gradient) @@ -466,6 +469,7 @@ gimp_operation_gradient_set_property (GObject *object, } gimp_operation_gradient_invalidate_cache (self); + g_clear_object (&gradient); } break; @@ -877,7 +881,7 @@ gradient_calc_shapeburst_dimpled_factor (GeglSampler *dist_sampler, static void gradient_render_pixel (gdouble x, gdouble y, - GimpRGB *color, + GimpRGB *rgb, gpointer render_data) { RenderBlendData *rbd = render_data; @@ -990,7 +994,7 @@ gradient_render_pixel (gdouble x, case GIMP_REPEAT_TRUNCATE: if (factor < 0.0 || factor > 1.0) { - gimp_rgba_set (color, 0.0, 0.0, 0.0, 0.0); + gimp_rgba_set (rgb, 0.0, 0.0, 0.0, 0.0); return; } break; @@ -1002,16 +1006,22 @@ gradient_render_pixel (gdouble x, { factor = CLAMP (factor, 0.0, 1.0); - *color = + *rgb = rbd->gradient_cache[ROUND (factor * (rbd->gradient_cache_size - 1))]; } else { + GeglColor *color = NULL; + rbd->last_seg = gimp_gradient_get_color_at (rbd->gradient, NULL, rbd->last_seg, factor, rbd->reverse, rbd->blend_color_space, - color); + &color); + if (color) + gegl_color_get_pixel (color, babl_format ("R'G'B'A double"), rgb); + + g_clear_object (&color); } } @@ -1270,13 +1280,18 @@ gimp_operation_gradient_validate_cache (GimpOperationGradient *self) for (i = 0; i < self->gradient_cache_size; i++) { - gdouble factor = (gdouble) i / (gdouble) (self->gradient_cache_size - 1); + GeglColor *color = NULL; + gdouble factor = (gdouble) i / (gdouble) (self->gradient_cache_size - 1); last_seg = gimp_gradient_get_color_at (self->gradient, NULL, last_seg, factor, self->gradient_reverse, self->gradient_blend_color_space, - self->gradient_cache + i); + &color); + if (color) + gegl_color_get_pixel (color, babl_format ("R'G'B'A double"), self->gradient_cache + i); + + g_clear_object (&color); } g_mutex_unlock (&self->gradient_cache_mutex); diff --git a/app/paint/gimppaintbrush.c b/app/paint/gimppaintbrush.c index 510186fec7..df479a7e6d 100644 --- a/app/paint/gimppaintbrush.c +++ b/app/paint/gimppaintbrush.c @@ -188,6 +188,7 @@ gimp_paintbrush_real_get_paint_params (GimpPaintbrush *paintbrush, GimpBrushCore *brush_core = GIMP_BRUSH_CORE (paintbrush); GimpContext *context = GIMP_CONTEXT (paint_options); GimpImage *image = gimp_item_get_image (GIMP_ITEM (drawable)); + GeglColor *color = NULL; *paint_mode = gimp_context_get_paint_mode (context); @@ -195,13 +196,16 @@ gimp_paintbrush_real_get_paint_params (GimpPaintbrush *paintbrush, gimp_paint_options_get_gradient_color (paint_options, image, grad_point, paint_core->pixel_dist, - paint_color)) + &color)) { + gegl_color_get_pixel (color, babl_format ("R'G'B'A double"), paint_color); /* optionally take the color from the current gradient */ gimp_pickable_srgb_to_image_color (GIMP_PICKABLE (drawable), paint_color, paint_color); *paint_appl_mode = GIMP_PAINT_INCREMENTAL; + + g_clear_object (&color); } else if (brush_core->brush && gimp_brush_get_pixmap (brush_core->brush)) { @@ -215,7 +219,6 @@ gimp_paintbrush_real_get_paint_params (GimpPaintbrush *paintbrush, else { /* otherwise fill the area with the foreground color */ - GeglColor *color; color = gimp_context_get_foreground (context); gegl_color_get_rgba_with_space (color, &paint_color->r, &paint_color->g, &paint_color->b, &paint_color->a, NULL); diff --git a/app/paint/gimppaintoptions.c b/app/paint/gimppaintoptions.c index c230152097..511a467046 100644 --- a/app/paint/gimppaintoptions.c +++ b/app/paint/gimppaintoptions.c @@ -1054,17 +1054,17 @@ gimp_paint_options_get_jitter (GimpPaintOptions *paint_options, } gboolean -gimp_paint_options_get_gradient_color (GimpPaintOptions *paint_options, - GimpImage *image, - gdouble grad_point, - gdouble pixel_dist, - GimpRGB *color) +gimp_paint_options_get_gradient_color (GimpPaintOptions *paint_options, + GimpImage *image, + gdouble grad_point, + gdouble pixel_dist, + GeglColor **color) { GimpDynamics *dynamics; g_return_val_if_fail (GIMP_IS_PAINT_OPTIONS (paint_options), FALSE); g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE); - g_return_val_if_fail (color != NULL, FALSE); + g_return_val_if_fail (color != NULL && *color == NULL, FALSE); dynamics = gimp_context_get_dynamics (GIMP_CONTEXT (paint_options)); diff --git a/app/paint/gimppaintoptions.h b/app/paint/gimppaintoptions.h index a2083a0cc7..76b8b3488a 100644 --- a/app/paint/gimppaintoptions.h +++ b/app/paint/gimppaintoptions.h @@ -149,7 +149,7 @@ gboolean gimp_paint_options_get_gradient_color (GimpPaintOptions *options, GimpImage *image, gdouble grad_point, gdouble pixel_dist, - GimpRGB *color); + GeglColor **color); GimpBrushApplicationMode gimp_paint_options_get_brush_mode (GimpPaintOptions *options); diff --git a/app/paint/gimpsmudge.c b/app/paint/gimpsmudge.c index b8da702b94..b8a6b60cfe 100644 --- a/app/paint/gimpsmudge.c +++ b/app/paint/gimpsmudge.c @@ -366,8 +366,8 @@ gimp_smudge_motion (GimpPaintCore *paint_core, gdouble flow; gdouble grad_point; /* brush color */ - GimpRGB brush_color; - GimpRGB *brush_color_ptr; /* whether use single color or pixmap */ + GeglColor *brush_color = NULL; + GimpRGB brush_rgb; /* whether use single color or pixmap */ /* accum buffer */ gint x, y; GeglBuffer *accum_buffer; @@ -441,7 +441,6 @@ gimp_smudge_motion (GimpPaintCore *paint_core, fade_point); /* Get current gradient color, brush pixmap, or foreground color */ - brush_color_ptr = &brush_color; if (gimp_paint_options_get_gradient_color (paint_options, image, grad_point, paint_core->pixel_dist, @@ -451,23 +450,12 @@ gimp_smudge_motion (GimpPaintCore *paint_core, } else if (brush_core->brush && gimp_brush_get_pixmap (brush_core->brush)) { - brush_color_ptr = NULL; } else { - GeglColor *color; - - color = gimp_context_get_foreground (context); - gegl_color_get_rgba_with_space (color, &brush_color.r, &brush_color.g, &brush_color.b, &brush_color.a, NULL); + brush_color = g_object_ref (gimp_context_get_foreground (context)); } - /* Convert to linear RGBA */ - if (brush_color_ptr) - gimp_pickable_rgb_to_pixel (dest_pickable, - &brush_color, - babl_format ("RGBA double"), - &brush_color); - n_strokes = gimp_symmetry_get_size (sym); for (i = 0; i < n_strokes; i++) { @@ -514,7 +502,7 @@ gimp_smudge_motion (GimpPaintCore *paint_core, * gimp_gegl_smudge_with_paint() instead of calling * gegl_buffer_set_color() to reduce gegl's internal processing. */ - if (! brush_color_ptr && flow > 0.0) + if (! brush_color && flow > 0.0) { gimp_brush_core_color_area_with_pixmap (brush_core, drawable, &coords, @@ -524,6 +512,10 @@ gimp_smudge_motion (GimpPaintCore *paint_core, TRUE); } + if (brush_color) + /* Convert to linear RGBA */ + gegl_color_get_pixel (brush_color, babl_format ("RGBA double"), &brush_rgb); + gimp_gegl_smudge_with_paint (accum_buffer, GEGL_RECTANGLE (paint_buffer_x - x, paint_buffer_y - y, @@ -536,7 +528,7 @@ gimp_smudge_motion (GimpPaintCore *paint_core, dest_pickable_off_y, paint_buffer_width, paint_buffer_height), - brush_color_ptr, + brush_color ? &brush_rgb : NULL, paint_buffer, options->no_erasing, flow, @@ -559,6 +551,8 @@ gimp_smudge_motion (GimpPaintCore *paint_core, force, GIMP_PAINT_INCREMENTAL); } + + g_clear_object (&brush_color); } static void diff --git a/app/pdb/gradient-cmds.c b/app/pdb/gradient-cmds.c index 277faa26b8..28d258a5eb 100644 --- a/app/pdb/gradient-cmds.c +++ b/app/pdb/gradient-cmds.c @@ -21,15 +21,12 @@ #include "stamp-pdbgen.h" -#include #include #include #include -#include "libgimpcolor/gimpcolor.h" - #include "libgimpbase/gimpbase.h" #include "pdb-types.h" @@ -178,23 +175,27 @@ gradient_get_uniform_samples_invoker (GimpProcedure *procedure, num_color_samples = num_samples * 4; - sample = color_samples = g_new (gdouble, num_color_samples); + sample = color_samples = g_new0 (gdouble, num_color_samples); while (num_samples--) { - GimpRGB color; + GeglColor *color = NULL; seg = gimp_gradient_get_color_at (gradient, context, seg, pos, reverse, GIMP_GRADIENT_BLEND_RGB_PERCEPTUAL, &color); + /* XXX "float" in PDB are in fact double. */ + if (color) + gegl_color_get_pixel (color, babl_format ("R'G'B'A double"), sample); + /* TODO: should we really return a list of floats? What about a list + * of GeglColor? + */ - *sample++ = color.r; - *sample++ = color.g; - *sample++ = color.b; - *sample++ = color.a; + sample += 4; + pos += delta; - pos += delta; + g_clear_object (&color); } } else @@ -244,11 +245,11 @@ gradient_get_custom_samples_invoker (GimpProcedure *procedure, num_color_samples = num_samples * 4; - sample = color_samples = g_new (gdouble, num_color_samples); + sample = color_samples = g_new0 (gdouble, num_color_samples); while (num_samples--) { - GimpRGB color; + GeglColor *color = NULL; seg = gimp_gradient_get_color_at (gradient, context, seg, *positions, @@ -256,12 +257,13 @@ gradient_get_custom_samples_invoker (GimpProcedure *procedure, GIMP_GRADIENT_BLEND_RGB_PERCEPTUAL, &color); - *sample++ = color.r; - *sample++ = color.g; - *sample++ = color.b; - *sample++ = color.a; + if (color) + gegl_color_get_pixel (color, babl_format ("R'G'B'A double"), sample); + sample += 4; positions++; + + g_clear_object (&color); } } else @@ -292,8 +294,7 @@ gradient_segment_get_left_color_invoker (GimpProcedure *procedure, GimpValueArray *return_vals; GimpGradient *gradient; gint segment; - GimpRGB color = { 0.0, 0.0, 0.0, 1.0 }; - gdouble opacity = 0.0; + GeglColor *color = NULL; gradient = g_value_get_object (gimp_value_array_index (args, 0)); segment = g_value_get_int (gimp_value_array_index (args, 1)); @@ -305,10 +306,7 @@ gradient_segment_get_left_color_invoker (GimpProcedure *procedure, seg = gimp_gradient_segment_get_nth (gradient->segments, segment); if (seg) - { - gimp_gradient_segment_get_left_color (gradient, seg, &color); - opacity = color.a * 100.0; - } + color = g_object_ref (gimp_gradient_segment_get_left_color (gradient, seg)); else success = FALSE; } @@ -317,10 +315,7 @@ gradient_segment_get_left_color_invoker (GimpProcedure *procedure, error ? *error : NULL); if (success) - { - gimp_value_set_rgb (gimp_value_array_index (return_vals, 1), &color); - g_value_set_double (gimp_value_array_index (return_vals, 2), opacity); - } + g_value_take_object (gimp_value_array_index (return_vals, 1), color); return return_vals; } @@ -336,30 +331,23 @@ gradient_segment_set_left_color_invoker (GimpProcedure *procedure, gboolean success = TRUE; GimpGradient *gradient; gint segment; - GimpRGB color; - gdouble opacity; + GeglColor *color; gradient = g_value_get_object (gimp_value_array_index (args, 0)); segment = g_value_get_int (gimp_value_array_index (args, 1)); - gimp_value_get_rgb (gimp_value_array_index (args, 2), &color); - opacity = g_value_get_double (gimp_value_array_index (args, 3)); + color = g_value_get_object (gimp_value_array_index (args, 2)); if (success) { if (gimp_data_is_writable (GIMP_DATA (gradient))) { - GimpGradientSegment *seg = gimp_gradient_segment_get_nth (gradient->segments, segment); + GimpGradientSegment *seg = gimp_gradient_segment_get_nth (gradient->segments, segment); - if (seg) - { - color.a = opacity / 100.0; - gimp_gradient_segment_set_left_color (gradient, seg, &color); - } - else - { + if (seg) + gimp_gradient_segment_set_left_color (gradient, seg, color); + else success = FALSE; } - } else { success = FALSE; @@ -382,8 +370,7 @@ gradient_segment_get_right_color_invoker (GimpProcedure *procedure, GimpValueArray *return_vals; GimpGradient *gradient; gint segment; - GimpRGB color = { 0.0, 0.0, 0.0, 1.0 }; - gdouble opacity = 0.0; + GeglColor *color = NULL; gradient = g_value_get_object (gimp_value_array_index (args, 0)); segment = g_value_get_int (gimp_value_array_index (args, 1)); @@ -395,10 +382,7 @@ gradient_segment_get_right_color_invoker (GimpProcedure *procedure, seg = gimp_gradient_segment_get_nth (gradient->segments, segment); if (seg) - { - gimp_gradient_segment_get_right_color (gradient, seg, &color); - opacity = color.a * 100.0; - } + color = g_object_ref (gimp_gradient_segment_get_right_color (gradient, seg)); else success = FALSE; } @@ -407,10 +391,7 @@ gradient_segment_get_right_color_invoker (GimpProcedure *procedure, error ? *error : NULL); if (success) - { - gimp_value_set_rgb (gimp_value_array_index (return_vals, 1), &color); - g_value_set_double (gimp_value_array_index (return_vals, 2), opacity); - } + g_value_take_object (gimp_value_array_index (return_vals, 1), color); return return_vals; } @@ -426,13 +407,11 @@ gradient_segment_set_right_color_invoker (GimpProcedure *procedure, gboolean success = TRUE; GimpGradient *gradient; gint segment; - GimpRGB color; - gdouble opacity; + GeglColor *color; gradient = g_value_get_object (gimp_value_array_index (args, 0)); segment = g_value_get_int (gimp_value_array_index (args, 1)); - gimp_value_get_rgb (gimp_value_array_index (args, 2), &color); - opacity = g_value_get_double (gimp_value_array_index (args, 3)); + color = g_value_get_object (gimp_value_array_index (args, 2)); if (success) { @@ -441,10 +420,7 @@ gradient_segment_set_right_color_invoker (GimpProcedure *procedure, GimpGradientSegment *seg = gimp_gradient_segment_get_nth (gradient->segments, segment); if (seg) - { - color.a = opacity / 100.0; - gimp_gradient_segment_set_right_color (gradient, seg, &color); - } + gimp_gradient_segment_set_right_color (gradient, seg, color); else success = FALSE; } @@ -1156,8 +1132,8 @@ gradient_segment_range_blend_colors_invoker (GimpProcedure *procedure, if (start_seg && end_seg) gimp_gradient_segment_range_blend (gradient, start_seg, end_seg, - &start_seg->left_color, - &end_seg->right_color, + start_seg->left_color, + end_seg->right_color, TRUE, FALSE); else success = FALSE; @@ -1202,8 +1178,8 @@ gradient_segment_range_blend_opacity_invoker (GimpProcedure *procedure, if (start_seg && end_seg) gimp_gradient_segment_range_blend (gradient, start_seg, end_seg, - &start_seg->left_color, - &end_seg->right_color, + start_seg->left_color, + end_seg->right_color, FALSE, TRUE); else success = FALSE; @@ -1493,18 +1469,11 @@ register_gradient_procs (GimpPDB *pdb) 0, G_MAXINT32, 0, GIMP_PARAM_READWRITE)); gimp_procedure_add_return_value (procedure, - gimp_param_spec_rgb ("color", - "color", - "The return color", - FALSE, - NULL, - GIMP_PARAM_READWRITE)); - gimp_procedure_add_return_value (procedure, - g_param_spec_double ("opacity", - "opacity", - "The opacity of the endpoint", - -G_MAXDOUBLE, G_MAXDOUBLE, 0, - GIMP_PARAM_READWRITE)); + gegl_param_spec_color ("color", + "color", + "The return color", + NULL, + GIMP_PARAM_READWRITE)); gimp_pdb_register_procedure (pdb, procedure); g_object_unref (procedure); @@ -1516,7 +1485,7 @@ register_gradient_procs (GimpPDB *pdb) "gimp-gradient-segment-set-left-color"); gimp_procedure_set_static_help (procedure, "Sets the left endpoint color of a segment", - "Sets the color of the left endpoint the indexed segment of the gradient.\n" + "Sets the color of the left endpoint the indexed segment of the gradient. The alpha channel of the [class@Gegl.Color] is taken into account.\n" "Returns an error when gradient is not editable or index is out of range.", NULL); gimp_procedure_set_static_attribution (procedure, @@ -1536,18 +1505,11 @@ register_gradient_procs (GimpPDB *pdb) 0, G_MAXINT32, 0, GIMP_PARAM_READWRITE)); gimp_procedure_add_argument (procedure, - gimp_param_spec_rgb ("color", - "color", - "The color to set", - FALSE, - NULL, - GIMP_PARAM_READWRITE)); - gimp_procedure_add_argument (procedure, - g_param_spec_double ("opacity", - "opacity", - "The opacity to set for the endpoint", - 0, 100.0, 0, - GIMP_PARAM_READWRITE)); + gegl_param_spec_color ("color", + "color", + "The color to set", + NULL, + GIMP_PARAM_READWRITE)); gimp_pdb_register_procedure (pdb, procedure); g_object_unref (procedure); @@ -1579,18 +1541,11 @@ register_gradient_procs (GimpPDB *pdb) 0, G_MAXINT32, 0, GIMP_PARAM_READWRITE)); gimp_procedure_add_return_value (procedure, - gimp_param_spec_rgb ("color", - "color", - "The return color", - FALSE, - NULL, - GIMP_PARAM_READWRITE)); - gimp_procedure_add_return_value (procedure, - g_param_spec_double ("opacity", - "opacity", - "The opacity of the endpoint", - -G_MAXDOUBLE, G_MAXDOUBLE, 0, - GIMP_PARAM_READWRITE)); + gegl_param_spec_color ("color", + "color", + "The return color", + NULL, + GIMP_PARAM_READWRITE)); gimp_pdb_register_procedure (pdb, procedure); g_object_unref (procedure); @@ -1602,7 +1557,7 @@ register_gradient_procs (GimpPDB *pdb) "gimp-gradient-segment-set-right-color"); gimp_procedure_set_static_help (procedure, "Sets the right endpoint color of the segment", - "Sets the right endpoint color of the segment of the gradient.\n" + "Sets the right endpoint color of the segment of the gradient. The alpha channel of the [class@Gegl.Color] is taken into account.\n" "Returns an error when gradient is not editable or segment index is out of range.", NULL); gimp_procedure_set_static_attribution (procedure, @@ -1622,18 +1577,11 @@ register_gradient_procs (GimpPDB *pdb) 0, G_MAXINT32, 0, GIMP_PARAM_READWRITE)); gimp_procedure_add_argument (procedure, - gimp_param_spec_rgb ("color", - "color", - "The color to set", - FALSE, - NULL, - GIMP_PARAM_READWRITE)); - gimp_procedure_add_argument (procedure, - g_param_spec_double ("opacity", - "opacity", - "The opacity to set for the endpoint", - 0, 100.0, 0, - GIMP_PARAM_READWRITE)); + gegl_param_spec_color ("color", + "color", + "The color to set", + NULL, + GIMP_PARAM_READWRITE)); gimp_pdb_register_procedure (pdb, procedure); g_object_unref (procedure); diff --git a/app/tools/gimpgradienttool-editor.c b/app/tools/gimpgradienttool-editor.c index f0ccea001d..94fa55b493 100644 --- a/app/tools/gimpgradienttool-editor.c +++ b/app/tools/gimpgradienttool-editor.c @@ -22,6 +22,7 @@ #include #include "libgimpbase/gimpbase.h" +#include "libgimpcolor/gimpcolor.h" #include "libgimpmath/gimpmath.h" #include "libgimpwidgets/gimpwidgets.h" @@ -331,10 +332,7 @@ gimp_gradient_tool_editor_line_selection_changed (GimpToolLine *line, seg = gimp_gradient_tool_editor_handle_get_segment (gradient_tool, selection); - homogeneous = seg->right_color.r == seg->next->left_color.r && - seg->right_color.g == seg->next->left_color.g && - seg->right_color.b == seg->next->left_color.b && - seg->right_color.a == seg->next->left_color.a && + homogeneous = gimp_color_is_perceptually_identical (seg->right_color, seg->next->left_color) && seg->right_color_type == seg->next->left_color_type; gimp_chain_button_set_active ( @@ -401,7 +399,6 @@ gimp_gradient_tool_editor_color_entry_color_changed (GimpColorButton *button, GimpPaintOptions *paint_options = GIMP_PAINT_OPTIONS (options); gint selection; GeglColor *color; - GimpRGB rgb; Direction direction; GtkWidget *chain_button; GimpGradientSegment *seg; @@ -413,8 +410,6 @@ gimp_gradient_tool_editor_color_entry_color_changed (GimpColorButton *button, gimp_tool_line_get_selection (GIMP_TOOL_LINE (gradient_tool->widget)); color = gimp_color_button_get_color (button); - gegl_color_get_pixel (color, babl_format ("R'G'B'A double"), &rgb); - g_object_unref (color); direction = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (button), @@ -445,12 +440,14 @@ gimp_gradient_tool_editor_color_entry_color_changed (GimpColorButton *button, switch (selection) { case GIMP_TOOL_LINE_HANDLE_START: - seg->left_color = rgb; + g_clear_object (&seg->left_color); + seg->left_color = g_object_ref (color); seg->left_color_type = GIMP_GRADIENT_COLOR_FIXED; break; case GIMP_TOOL_LINE_HANDLE_END: - seg->right_color = rgb; + g_clear_object (&seg->right_color); + seg->right_color = g_object_ref (color); seg->right_color_type = GIMP_GRADIENT_COLOR_FIXED; break; @@ -459,7 +456,8 @@ gimp_gradient_tool_editor_color_entry_color_changed (GimpColorButton *button, (chain_button && gimp_chain_button_get_active (GIMP_CHAIN_BUTTON (chain_button)))) { - seg->right_color = rgb; + g_clear_object (&seg->right_color); + seg->right_color = gegl_color_duplicate (color); seg->right_color_type = GIMP_GRADIENT_COLOR_FIXED; } @@ -467,13 +465,16 @@ gimp_gradient_tool_editor_color_entry_color_changed (GimpColorButton *button, (chain_button && gimp_chain_button_get_active (GIMP_CHAIN_BUTTON (chain_button)))) { - seg->next->left_color = rgb; + g_clear_object (&seg->next->left_color); + seg->next->left_color = g_object_ref (color); seg->next->left_color_type = GIMP_GRADIENT_COLOR_FIXED; } } gimp_gradient_tool_editor_thaw_gradient (gradient_tool); gimp_gradient_tool_editor_end_edit (gradient_tool, FALSE); + + g_object_unref (color); } static void @@ -1574,8 +1575,7 @@ gimp_gradient_tool_editor_update_endpoint_gui (GimpGradientTool *gradient_tool, const gchar *title; gdouble x; gdouble y; - GeglColor *color; - GimpRGB rgb; + GeglColor *color = NULL; GimpGradientColor color_type; editable = gimp_gradient_tool_editor_is_gradient_editable (gradient_tool); @@ -1622,16 +1622,16 @@ gimp_gradient_tool_editor_update_endpoint_gui (GimpGradientTool *gradient_tool, case GIMP_TOOL_LINE_HANDLE_START: title = _("Start Endpoint"); - gimp_gradient_segment_get_left_flat_color (gradient_tool->gradient, context, - seg, &rgb); + color = gimp_gradient_segment_get_left_flat_color (gradient_tool->gradient, context, + seg); color_type = seg->left_color_type; break; case GIMP_TOOL_LINE_HANDLE_END: title = _("End Endpoint"); - gimp_gradient_segment_get_right_flat_color (gradient_tool->gradient, context, - seg, &rgb); + color = gimp_gradient_segment_get_right_flat_color (gradient_tool->gradient, context, + seg); color_type = seg->right_color_type; break; @@ -1644,11 +1644,7 @@ gimp_gradient_tool_editor_update_endpoint_gui (GimpGradientTool *gradient_tool, gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (gradient_tool->endpoint_se), 0, x); gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (gradient_tool->endpoint_se), 1, y); - color = gegl_color_new (NULL); - gegl_color_set_pixel (color, babl_format ("R'G'B'A double"), &rgb); - gimp_color_button_set_color ( - GIMP_COLOR_BUTTON (gradient_tool->endpoint_color_panel), color); - g_object_unref (color); + gimp_color_button_set_color (GIMP_COLOR_BUTTON (gradient_tool->endpoint_color_panel), color); gimp_int_combo_box_set_active ( GIMP_INT_COMBO_BOX (gradient_tool->endpoint_type_combo), color_type); @@ -1656,6 +1652,8 @@ gimp_gradient_tool_editor_update_endpoint_gui (GimpGradientTool *gradient_tool, gtk_widget_set_sensitive (gradient_tool->endpoint_type_combo, editable); gtk_widget_show (gradient_tool->endpoint_editor); + + g_object_unref (color); } static void @@ -1671,10 +1669,9 @@ gimp_gradient_tool_editor_update_stop_gui (GimpGradientTool *gradient_tool, gdouble min; gdouble max; gdouble value; - GeglColor *color; - GimpRGB left_color; + GeglColor *left_color; GimpGradientColor left_color_type; - GimpRGB right_color; + GeglColor *right_color; GimpGradientColor right_color_type; editable = gimp_gradient_tool_editor_is_gradient_editable (gradient_tool); @@ -1691,12 +1688,11 @@ gimp_gradient_tool_editor_update_stop_gui (GimpGradientTool *gradient_tool, max = seg->next->right; value = seg->right; - gimp_gradient_segment_get_right_flat_color (gradient_tool->gradient, context, - seg, &left_color); + left_color = gimp_gradient_segment_get_right_flat_color (gradient_tool->gradient, context, seg); left_color_type = seg->right_color_type; - gimp_gradient_segment_get_left_flat_color (gradient_tool->gradient, context, - seg->next, &right_color); + right_color = gimp_gradient_segment_get_left_flat_color (gradient_tool->gradient, context, + seg->next); right_color_type = seg->next->left_color_type; gimp_tool_gui_set_title (gradient_tool->gui, title); @@ -1706,17 +1702,13 @@ gimp_gradient_tool_editor_update_stop_gui (GimpGradientTool *gradient_tool, gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (gradient_tool->stop_se), 0, 100.0 * value); - color = gegl_color_new (NULL); - - gegl_color_set_pixel (color, babl_format ("R'G'B'A double"), &left_color); gimp_color_button_set_color ( - GIMP_COLOR_BUTTON (gradient_tool->stop_left_color_panel), color); + GIMP_COLOR_BUTTON (gradient_tool->stop_left_color_panel), left_color); gimp_int_combo_box_set_active ( GIMP_INT_COMBO_BOX (gradient_tool->stop_left_type_combo), left_color_type); - gegl_color_set_pixel (color, babl_format ("R'G'B'A double"), &right_color); gimp_color_button_set_color ( - GIMP_COLOR_BUTTON (gradient_tool->stop_right_color_panel), color); + GIMP_COLOR_BUTTON (gradient_tool->stop_right_color_panel), right_color); gimp_int_combo_box_set_active ( GIMP_INT_COMBO_BOX (gradient_tool->stop_right_type_combo), right_color_type); @@ -1731,7 +1723,8 @@ gimp_gradient_tool_editor_update_stop_gui (GimpGradientTool *gradient_tool, editable); g_free (title); - g_object_unref (color); + g_object_unref (left_color); + g_object_unref (right_color); gtk_widget_show (gradient_tool->stop_editor); } diff --git a/app/widgets/gimpgradienteditor.c b/app/widgets/gimpgradienteditor.c index 7739d4e6f2..8fa5f0878a 100644 --- a/app/widgets/gimpgradienteditor.c +++ b/app/widgets/gimpgradienteditor.c @@ -435,18 +435,23 @@ gimp_gradient_editor_init (GimpGradientEditor *editor) editor->hint_label4 = gradient_hint_label_add (GTK_BOX (hint_vbox)); /* Black, 50% Gray, White, Clear */ - gimp_rgba_set (&editor->saved_colors[0], 0.0, 0.0, 0.0, GIMP_OPACITY_OPAQUE); - gimp_rgba_set (&editor->saved_colors[1], 0.5, 0.5, 0.5, GIMP_OPACITY_OPAQUE); - gimp_rgba_set (&editor->saved_colors[2], 1.0, 1.0, 1.0, GIMP_OPACITY_OPAQUE); - gimp_rgba_set (&editor->saved_colors[3], 0.0, 0.0, 0.0, GIMP_OPACITY_TRANSPARENT); + editor->saved_colors[0] = gegl_color_new ("black"); + editor->saved_colors[1] = gegl_color_new ("gray"); + editor->saved_colors[2] = gegl_color_new ("white"); + editor->saved_colors[3] = gegl_color_new ("transparent"); /* Red, Yellow, Green, Cyan, Blue, Magenta */ - gimp_rgba_set (&editor->saved_colors[4], 1.0, 0.0, 0.0, GIMP_OPACITY_OPAQUE); - gimp_rgba_set (&editor->saved_colors[5], 1.0, 1.0, 0.0, GIMP_OPACITY_OPAQUE); - gimp_rgba_set (&editor->saved_colors[6], 0.0, 1.0, 0.0, GIMP_OPACITY_OPAQUE); - gimp_rgba_set (&editor->saved_colors[7], 0.0, 1.0, 1.0, GIMP_OPACITY_OPAQUE); - gimp_rgba_set (&editor->saved_colors[8], 0.0, 0.0, 1.0, GIMP_OPACITY_OPAQUE); - gimp_rgba_set (&editor->saved_colors[9], 1.0, 0.0, 1.0, GIMP_OPACITY_OPAQUE); + editor->saved_colors[4] = gegl_color_new ("red"); + editor->saved_colors[5] = gegl_color_new ("yellow"); + /* XXX: green in GEGL is 0 0.5 0, so we override it. */ + editor->saved_colors[6] = gegl_color_new ("green"); + gegl_color_set_rgba_with_space (editor->saved_colors[6], 0.0, 1.0, 0.0, GIMP_OPACITY_OPAQUE, NULL); + /* XXX: Cyan */ + editor->saved_colors[7] = gegl_color_new (NULL); + gegl_color_set_rgba_with_space (editor->saved_colors[7], 0.0, 1.0, 1.0, GIMP_OPACITY_OPAQUE, NULL); + editor->saved_colors[8] = gegl_color_new ("blue"); + /* XXX: what we defined Magenta is "fuchsia" in GEGL. */ + editor->saved_colors[9] = gegl_color_new ("fuchsia"); g_object_unref (transp); } @@ -479,6 +484,9 @@ gimp_gradient_editor_dispose (GObject *object) g_clear_object (&editor->zoom_gesture); + for (gint i = 0; i < GRAD_NUM_COLORS; i++) + g_clear_object (&editor->saved_colors[i]); + G_OBJECT_CLASS (parent_class)->dispose (object); } @@ -594,6 +602,7 @@ void gimp_gradient_editor_edit_left_color (GimpGradientEditor *editor) { GimpGradient *gradient; + GimpRGB rgb; g_return_if_fail (GIMP_IS_GRADIENT_EDITOR (editor)); @@ -607,6 +616,8 @@ gimp_gradient_editor_edit_left_color (GimpGradientEditor *editor) editor->saved_dirty = gimp_data_is_dirty (GIMP_DATA (gradient)); editor->saved_segments = gradient_editor_save_selection (editor); + gegl_color_get_pixel (editor->control_sel_l->left_color, babl_format ("R'G'B'A double"), + &rgb); editor->color_dialog = gimp_color_dialog_new (GIMP_VIEWABLE (gradient), GIMP_DATA_EDITOR (editor)->context, @@ -617,7 +628,7 @@ gimp_gradient_editor_edit_left_color (GimpGradientEditor *editor) GTK_WIDGET (editor), gimp_dialog_factory_get_singleton (), "gimp-gradient-editor-color-dialog", - &editor->control_sel_l->left_color, + &rgb, TRUE, TRUE); g_signal_connect (editor->color_dialog, "destroy", @@ -639,6 +650,7 @@ void gimp_gradient_editor_edit_right_color (GimpGradientEditor *editor) { GimpGradient *gradient; + GimpRGB rgb; g_return_if_fail (GIMP_IS_GRADIENT_EDITOR (editor)); @@ -652,6 +664,8 @@ gimp_gradient_editor_edit_right_color (GimpGradientEditor *editor) editor->saved_dirty = gimp_data_is_dirty (GIMP_DATA (gradient)); editor->saved_segments = gradient_editor_save_selection (editor); + gegl_color_get_pixel (editor->control_sel_l->right_color, babl_format ("R'G'B'A double"), + &rgb); editor->color_dialog = gimp_color_dialog_new (GIMP_VIEWABLE (gradient), GIMP_DATA_EDITOR (editor)->context, @@ -662,8 +676,7 @@ gimp_gradient_editor_edit_right_color (GimpGradientEditor *editor) GTK_WIDGET (editor), gimp_dialog_factory_get_singleton (), "gimp-gradient-editor-color-dialog", - &editor->control_sel_l->right_color, - TRUE, TRUE); + &rgb, TRUE, TRUE); g_signal_connect (editor->color_dialog, "destroy", G_CALLBACK (gtk_widget_destroyed), @@ -840,7 +853,7 @@ static void gradient_editor_drop_color (GtkWidget *widget, gint x, gint y, - const GimpRGB *color, + const GimpRGB *rgb, gpointer data) { GimpGradientEditor *editor = GIMP_GRADIENT_EDITOR (data); @@ -865,14 +878,14 @@ gradient_editor_drop_color (GtkWidget *widget, { lseg->right = xpos; lseg->middle = (lseg->left + lseg->right) / 2.0; - lseg->right_color = *color; + gegl_color_set_pixel (lseg->right_color, babl_format ("R'G'B'A double"), rgb); } if (rseg) { rseg->left = xpos; rseg->middle = (rseg->left + rseg->right) / 2.0; - rseg->left_color = *color; + gegl_color_set_pixel (rseg->left_color, babl_format ("R'G'B'A double"), rgb); } gimp_data_thaw (GIMP_DATA (gradient)); @@ -882,7 +895,7 @@ static void gradient_editor_control_drop_color (GtkWidget *widget, gint x, gint y, - const GimpRGB *color, + const GimpRGB *rgb, gpointer data) { GimpGradientEditor *editor = GIMP_GRADIENT_EDITOR (data); @@ -915,10 +928,10 @@ gradient_editor_control_drop_color (GtkWidget *widget, gimp_data_freeze (GIMP_DATA (gradient)); if (lseg) - lseg->right_color = *color; + gegl_color_set_pixel (lseg->right_color, babl_format ("R'G'B'A double"), rgb); if (rseg) - rseg->left_color = *color; + gegl_color_set_pixel (rseg->left_color, babl_format ("R'G'B'A double"), rgb); gimp_data_thaw (GIMP_DATA (gradient)); } @@ -1048,11 +1061,14 @@ gradient_editor_replace_selection (GimpGradientEditor *editor, static void gradient_editor_left_color_update (GimpColorDialog *dialog, - const GimpRGB *color, + const GimpRGB *rgb, GimpColorDialogState state, GimpGradientEditor *editor) { GimpGradient *gradient = GIMP_GRADIENT (GIMP_DATA_EDITOR (editor)->data); + GeglColor *color = gegl_color_new (NULL); + + gegl_color_set_pixel (color, babl_format ("R'G'B'A double"), rgb); switch (state) { @@ -1061,7 +1077,7 @@ gradient_editor_left_color_update (GimpColorDialog *dialog, editor->control_sel_l, editor->control_sel_r, color, - &editor->control_sel_r->right_color, + editor->control_sel_r->right_color, TRUE, TRUE); break; @@ -1070,7 +1086,7 @@ gradient_editor_left_color_update (GimpColorDialog *dialog, editor->control_sel_l, editor->control_sel_r, color, - &editor->control_sel_r->right_color, + editor->control_sel_r->right_color, TRUE, TRUE); gimp_gradient_segments_free (editor->saved_segments); gtk_widget_destroy (editor->color_dialog); @@ -1092,15 +1108,20 @@ gradient_editor_left_color_update (GimpColorDialog *dialog, gimp_editor_get_popup_data (GIMP_EDITOR (editor))); break; } + + g_object_unref (color); } static void gradient_editor_right_color_update (GimpColorDialog *dialog, - const GimpRGB *color, + const GimpRGB *rgb, GimpColorDialogState state, GimpGradientEditor *editor) { GimpGradient *gradient = GIMP_GRADIENT (GIMP_DATA_EDITOR (editor)->data); + GeglColor *color = gegl_color_new (NULL); + + gegl_color_set_pixel (color, babl_format ("R'G'B'A double"), rgb); switch (state) { @@ -1108,7 +1129,7 @@ gradient_editor_right_color_update (GimpColorDialog *dialog, gimp_gradient_segment_range_blend (gradient, editor->control_sel_l, editor->control_sel_r, - &editor->control_sel_l->left_color, + editor->control_sel_l->left_color, color, TRUE, TRUE); break; @@ -1117,7 +1138,7 @@ gradient_editor_right_color_update (GimpColorDialog *dialog, gimp_gradient_segment_range_blend (gradient, editor->control_sel_l, editor->control_sel_r, - &editor->control_sel_l->left_color, + editor->control_sel_l->left_color, color, TRUE, TRUE); gimp_gradient_segments_free (editor->saved_segments); @@ -1140,6 +1161,8 @@ gradient_editor_right_color_update (GimpColorDialog *dialog, gimp_editor_get_popup_data (GIMP_EDITOR (editor))); break; } + + g_object_unref (color); } @@ -1285,9 +1308,9 @@ view_set_hint (GimpGradientEditor *editor, gint x) { GimpDataEditor *data_editor = GIMP_DATA_EDITOR (editor); - GeglColor *color = gegl_color_new ("black"); - GimpRGB rgb; - GimpHSV hsv; + GeglColor *color = NULL; + gdouble rgb[4]; + gdouble hsv[3]; gdouble xpos; gchar *str1; gchar *str2; @@ -1298,21 +1321,24 @@ view_set_hint (GimpGradientEditor *editor, gimp_gradient_get_color_at (GIMP_GRADIENT (data_editor->data), data_editor->context, NULL, - xpos, FALSE, FALSE, &rgb); + xpos, FALSE, FALSE, &color); - gegl_color_set_pixel (color, babl_format ("R'G'B'A double"), &rgb); gimp_color_area_set_color (GIMP_COLOR_AREA (editor->current_color), color); - gimp_rgb_to_hsv (&rgb, &hsv); + gegl_color_get_pixel (color, babl_format ("R'G'B'A double"), rgb); + gegl_color_get_pixel (color, babl_format ("HSV double"), hsv); str1 = g_strdup_printf (_("Position: %0.4f"), xpos); - str2 = g_strdup_printf (_("RGB (%0.3f, %0.3f, %0.3f)"), - rgb.r, rgb.g, rgb.b); + /* TODO: Current hints are displaying sRGB values. Ideally we'd want to update + * the RGB space depending on the active image. + */ + str2 = g_strdup_printf (_("sRGB (%0.3f, %0.3f, %0.3f)"), + rgb[0], rgb[1], rgb[2]); str3 = g_strdup_printf (_("HSV (%0.1f, %0.1f, %0.1f)"), - hsv.h * 360.0, hsv.s * 100.0, hsv.v * 100.0); + hsv[0] * 360.0, hsv[1] * 100.0, hsv[2] * 100.0); str4 = g_strdup_printf (_("Luminance: %0.1f Opacity: %0.1f"), - GIMP_RGB_LUMINANCE (rgb.r, rgb.g, rgb.b) * 100.0, - rgb.a * 100.0); + GIMP_RGB_LUMINANCE (rgb[0], rgb[1], rgb[2]) * 100.0, + rgb[3] * 100.0); gradient_editor_set_hint (editor, str1, str2, str3, str4); @@ -1330,8 +1356,8 @@ view_pick_color (GimpGradientEditor *editor, gint x) { GimpDataEditor *data_editor = GIMP_DATA_EDITOR (editor); - GeglColor *color = gegl_color_new ("black"); - GimpRGB rgb; + GeglColor *color = NULL; + gdouble rgb[3]; gdouble xpos; gchar *str2; gchar *str3; @@ -1340,17 +1366,17 @@ view_pick_color (GimpGradientEditor *editor, gimp_gradient_get_color_at (GIMP_GRADIENT (data_editor->data), data_editor->context, NULL, - xpos, FALSE, FALSE, &rgb); + xpos, FALSE, FALSE, &color); - gegl_color_set_pixel (color, babl_format ("R'G'B'A double"), &rgb); gimp_color_area_set_color (GIMP_COLOR_AREA (editor->current_color), color); - str2 = g_strdup_printf (_("RGB (%d, %d, %d)"), - (gint) (rgb.r * 255.0), - (gint) (rgb.g * 255.0), - (gint) (rgb.b * 255.0)); + gegl_color_get_pixel (color, babl_format ("R'G'B' double"), rgb); + str2 = g_strdup_printf (_("sRGB (%d, %d, %d)"), + (gint) (rgb[0] * 255.0), + (gint) (rgb[1] * 255.0), + (gint) (rgb[2] * 255.0)); - str3 = g_strdup_printf ("(%0.3f, %0.3f, %0.3f)", rgb.r, rgb.g, rgb.b); + str3 = g_strdup_printf ("(%0.3f, %0.3f, %0.3f)", rgb[0], rgb[1], rgb[2]); if (pick_target == GIMP_COLOR_PICK_TARGET_FOREGROUND) { diff --git a/app/widgets/gimpgradienteditor.h b/app/widgets/gimpgradienteditor.h index 98dfff27f2..b829905813 100644 --- a/app/widgets/gimpgradienteditor.h +++ b/app/widgets/gimpgradienteditor.h @@ -83,7 +83,7 @@ struct _GimpGradientEditor GimpGradientBlendColorSpace blend_color_space; /* Saved colors */ - GimpRGB saved_colors[GRAD_NUM_COLORS]; + GeglColor *saved_colors[GRAD_NUM_COLORS]; /* Color dialog */ GtkWidget *color_dialog; diff --git a/app/widgets/gimpgradientselect.c b/app/widgets/gimpgradientselect.c index 4bd64408e2..db78dcf699 100644 --- a/app/widgets/gimpgradientselect.c +++ b/app/widgets/gimpgradientselect.c @@ -145,7 +145,6 @@ gimp_gradient_select_run_callback (GimpPdbDialog *dialog, GimpGradientSegment *seg = NULL; gdouble *values, *pv; gdouble pos, delta; - GimpRGB color; gint i; GimpArray *array; GimpValueArray *return_vals; @@ -159,17 +158,19 @@ gimp_gradient_select_run_callback (GimpPdbDialog *dialog, while (i--) { + GeglColor *color = NULL; + seg = gimp_gradient_get_color_at (gradient, dialog->caller_context, seg, pos, FALSE, GIMP_GRADIENT_BLEND_RGB_PERCEPTUAL, &color); - *pv++ = color.r; - *pv++ = color.g; - *pv++ = color.b; - *pv++ = color.a; + gegl_color_get_pixel (color, babl_format ("R'G'B'A double"), pv); + pv += 4; pos += delta; + + g_object_unref (color); } array = gimp_array_new ((guint8 *) values, diff --git a/app/widgets/gimpviewrenderer.c b/app/widgets/gimpviewrenderer.c index b4526d79bf..0c87e6ccb0 100644 --- a/app/widgets/gimpviewrenderer.c +++ b/app/widgets/gimpviewrenderer.c @@ -550,6 +550,14 @@ gimp_view_renderer_set_color_config (GimpViewRenderer *renderer, } } +GimpColorConfig * +gimp_view_renderer_get_color_config (GimpViewRenderer *renderer) +{ + g_return_val_if_fail (GIMP_IS_VIEW_RENDERER (renderer), NULL); + + return renderer->priv->color_config; +} + void gimp_view_renderer_invalidate (GimpViewRenderer *renderer) { diff --git a/app/widgets/gimpviewrenderer.h b/app/widgets/gimpviewrenderer.h index 6d14533700..18b48166fd 100644 --- a/app/widgets/gimpviewrenderer.h +++ b/app/widgets/gimpviewrenderer.h @@ -125,6 +125,8 @@ void gimp_view_renderer_set_background (GimpViewRenderer *renderer, const gchar *icon_name); void gimp_view_renderer_set_color_config (GimpViewRenderer *renderer, GimpColorConfig *color_config); +GimpColorConfig * + gimp_view_renderer_get_color_config (GimpViewRenderer *renderer); void gimp_view_renderer_invalidate (GimpViewRenderer *renderer); void gimp_view_renderer_update (GimpViewRenderer *renderer); diff --git a/app/widgets/gimpviewrenderergradient.c b/app/widgets/gimpviewrenderergradient.c index 6baaf3ec6b..5ef7c08f6f 100644 --- a/app/widgets/gimpviewrenderergradient.c +++ b/app/widgets/gimpviewrenderergradient.c @@ -158,22 +158,27 @@ gimp_view_renderer_gradient_render (GimpViewRenderer *renderer, GimpViewRendererGradient *rendergrad = GIMP_VIEW_RENDERER_GRADIENT (renderer); GimpGradient *gradient = GIMP_GRADIENT (renderer->viewable); GimpGradientSegment *seg = NULL; - GimpColorTransform *transform; + GimpColorConfig *color_config; + const Babl *dest_space; guchar *buf; guchar *dest; gint dest_stride; gint x; gint y; gdouble dx, cur_x; - GimpRGB color; buf = g_alloca (4 * renderer->width); dx = (rendergrad->right - rendergrad->left) / (renderer->width - 1); cur_x = rendergrad->left; + color_config = gimp_view_renderer_get_color_config (renderer); + + g_return_if_fail (color_config != NULL); + + dest_space = gimp_widget_get_render_space (widget, color_config); for (x = 0, dest = buf; x < renderer->width; x++, dest += 4) { - guchar r, g, b, a; + GeglColor *color = NULL; seg = gimp_gradient_get_color_at (gradient, renderer->context, seg, cur_x, @@ -182,9 +187,14 @@ gimp_view_renderer_gradient_render (GimpViewRenderer *renderer, &color); cur_x += dx; - gimp_rgba_get_uchar (&color, &r, &g, &b, &a); + /* This is only for rendering the gradient on thumbnails or small + * previews, so cairo-ARGB32 is probably enough. + */ + gegl_color_get_pixel (color, + babl_format_with_space ("cairo-ARGB32", dest_space), + dest); - GIMP_CAIRO_ARGB32_SET_PIXEL (dest, r, g, b, a); + g_object_unref (color); } if (! renderer->surface) @@ -197,20 +207,8 @@ gimp_view_renderer_gradient_render (GimpViewRenderer *renderer, dest = cairo_image_surface_get_data (renderer->surface); dest_stride = cairo_image_surface_get_stride (renderer->surface); - transform = gimp_view_renderer_get_color_transform (renderer, widget, - babl_format ("cairo-ARGB32"), - babl_format ("cairo-ARGB32")); - - if (transform) - gimp_color_transform_process_pixels (transform, - babl_format ("cairo-ARGB32"), buf, - babl_format ("cairo-ARGB32"), buf, - renderer->width); - for (y = 0; y < renderer->height; y++, dest += dest_stride) - { - memcpy (dest, buf, renderer->width * 4); - } + memcpy (dest, buf, renderer->width * 4); cairo_surface_mark_dirty (renderer->surface); } diff --git a/libgimp/gimpgradient_pdb.c b/libgimp/gimpgradient_pdb.c index 4b93c992d8..3b00c2143c 100644 --- a/libgimp/gimpgradient_pdb.c +++ b/libgimp/gimpgradient_pdb.c @@ -268,27 +268,23 @@ gimp_gradient_get_custom_samples (GimpGradient *gradient, * gimp_gradient_segment_get_left_color: * @gradient: The gradient. * @segment: The index of a segment within the gradient. - * @color: (out caller-allocates): The return color. - * @opacity: (out): The opacity of the endpoint. * * Gets the left endpoint color of the segment * * Gets the left endpoint color of the indexed segment of the gradient. * Returns an error when the segment index is out of range. * - * Returns: TRUE on success. + * Returns: (transfer full): The return color. * * Since: 2.2 **/ -gboolean +GeglColor * gimp_gradient_segment_get_left_color (GimpGradient *gradient, - gint segment, - GimpRGB *color, - gdouble *opacity) + gint segment) { GimpValueArray *args; GimpValueArray *return_vals; - gboolean success = TRUE; + GeglColor *color = NULL; args = gimp_value_array_new_from_types (NULL, GIMP_TYPE_GRADIENT, gradient, @@ -300,19 +296,12 @@ gimp_gradient_segment_get_left_color (GimpGradient *gradient, args); gimp_value_array_unref (args); - *opacity = 0.0; - - success = GIMP_VALUES_GET_ENUM (return_vals, 0) == GIMP_PDB_SUCCESS; - - if (success) - { - GIMP_VALUES_GET_RGB (return_vals, 1, &*color); - *opacity = GIMP_VALUES_GET_DOUBLE (return_vals, 2); - } + 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; } /** @@ -320,12 +309,12 @@ gimp_gradient_segment_get_left_color (GimpGradient *gradient, * @gradient: The gradient. * @segment: The index of a segment within the gradient. * @color: The color to set. - * @opacity: The opacity to set for the endpoint. * * Sets the left endpoint color of a segment * * Sets the color of the left endpoint the indexed segment of the - * gradient. + * gradient. The alpha channel of the [class@Gegl.Color] is taken into + * account. * Returns an error when gradient is not editable or index is out of * range. * @@ -334,10 +323,9 @@ gimp_gradient_segment_get_left_color (GimpGradient *gradient, * Since: 2.2 **/ gboolean -gimp_gradient_segment_set_left_color (GimpGradient *gradient, - gint segment, - const GimpRGB *color, - gdouble opacity) +gimp_gradient_segment_set_left_color (GimpGradient *gradient, + gint segment, + GeglColor *color) { GimpValueArray *args; GimpValueArray *return_vals; @@ -346,8 +334,7 @@ gimp_gradient_segment_set_left_color (GimpGradient *gradient, args = gimp_value_array_new_from_types (NULL, GIMP_TYPE_GRADIENT, gradient, G_TYPE_INT, segment, - GIMP_TYPE_RGB, color, - G_TYPE_DOUBLE, opacity, + GEGL_TYPE_COLOR, color, G_TYPE_NONE); return_vals = _gimp_pdb_run_procedure_array (gimp_get_pdb (), @@ -366,8 +353,6 @@ gimp_gradient_segment_set_left_color (GimpGradient *gradient, * gimp_gradient_segment_get_right_color: * @gradient: The gradient. * @segment: The index of a segment within the gradient. - * @color: (out caller-allocates): The return color. - * @opacity: (out): The opacity of the endpoint. * * Gets the right endpoint color of the segment * @@ -375,19 +360,17 @@ gimp_gradient_segment_set_left_color (GimpGradient *gradient, * gradient. * Returns an error when the segment index is out of range. * - * Returns: TRUE on success. + * Returns: (transfer full): The return color. * * Since: 2.2 **/ -gboolean +GeglColor * gimp_gradient_segment_get_right_color (GimpGradient *gradient, - gint segment, - GimpRGB *color, - gdouble *opacity) + gint segment) { GimpValueArray *args; GimpValueArray *return_vals; - gboolean success = TRUE; + GeglColor *color = NULL; args = gimp_value_array_new_from_types (NULL, GIMP_TYPE_GRADIENT, gradient, @@ -399,19 +382,12 @@ gimp_gradient_segment_get_right_color (GimpGradient *gradient, args); gimp_value_array_unref (args); - *opacity = 0.0; - - success = GIMP_VALUES_GET_ENUM (return_vals, 0) == GIMP_PDB_SUCCESS; - - if (success) - { - GIMP_VALUES_GET_RGB (return_vals, 1, &*color); - *opacity = GIMP_VALUES_GET_DOUBLE (return_vals, 2); - } + 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; } /** @@ -419,11 +395,11 @@ gimp_gradient_segment_get_right_color (GimpGradient *gradient, * @gradient: The gradient. * @segment: The index of a segment within the gradient. * @color: The color to set. - * @opacity: The opacity to set for the endpoint. * * Sets the right endpoint color of the segment * - * Sets the right endpoint color of the segment of the gradient. + * Sets the right endpoint color of the segment of the gradient. The + * alpha channel of the [class@Gegl.Color] is taken into account. * Returns an error when gradient is not editable or segment index is * out of range. * @@ -432,10 +408,9 @@ gimp_gradient_segment_get_right_color (GimpGradient *gradient, * Since: 2.2 **/ gboolean -gimp_gradient_segment_set_right_color (GimpGradient *gradient, - gint segment, - const GimpRGB *color, - gdouble opacity) +gimp_gradient_segment_set_right_color (GimpGradient *gradient, + gint segment, + GeglColor *color) { GimpValueArray *args; GimpValueArray *return_vals; @@ -444,8 +419,7 @@ gimp_gradient_segment_set_right_color (GimpGradient *gradient, args = gimp_value_array_new_from_types (NULL, GIMP_TYPE_GRADIENT, gradient, G_TYPE_INT, segment, - GIMP_TYPE_RGB, color, - G_TYPE_DOUBLE, opacity, + GEGL_TYPE_COLOR, color, G_TYPE_NONE); return_vals = _gimp_pdb_run_procedure_array (gimp_get_pdb (), diff --git a/libgimp/gimpgradient_pdb.h b/libgimp/gimpgradient_pdb.h index e2fdc5a7f4..9520485729 100644 --- a/libgimp/gimpgradient_pdb.h +++ b/libgimp/gimpgradient_pdb.h @@ -46,22 +46,16 @@ gboolean gimp_gradient_get_custom_samples (GimpGradient gboolean reverse, gint *num_color_samples, gdouble **color_samples); -gboolean gimp_gradient_segment_get_left_color (GimpGradient *gradient, - gint segment, - GimpRGB *color, - gdouble *opacity); +GeglColor* gimp_gradient_segment_get_left_color (GimpGradient *gradient, + gint segment); gboolean gimp_gradient_segment_set_left_color (GimpGradient *gradient, gint segment, - const GimpRGB *color, - gdouble opacity); -gboolean gimp_gradient_segment_get_right_color (GimpGradient *gradient, - gint segment, - GimpRGB *color, - gdouble *opacity); + GeglColor *color); +GeglColor* gimp_gradient_segment_get_right_color (GimpGradient *gradient, + gint segment); gboolean gimp_gradient_segment_set_right_color (GimpGradient *gradient, gint segment, - const GimpRGB *color, - gdouble opacity); + GeglColor *color); gboolean gimp_gradient_segment_get_left_pos (GimpGradient *gradient, gint segment, gdouble *pos); diff --git a/libgimpcolor/gimpcolor-parse.c b/libgimpcolor/gimpcolor-parse.c new file mode 100644 index 0000000000..017a71e67e --- /dev/null +++ b/libgimpcolor/gimpcolor-parse.c @@ -0,0 +1,481 @@ +/* LIBGIMP - The GIMP Library + * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball + * + * gimpcolor-parse.c + * Copyright (C) 2023 Jehan + * + * Some of the code in here was inspired and partly copied from pango + * and librsvg. + * + * This library 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 3 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + */ + +#include "config.h" + +#include +#include +#include +#include + +#include "gimpcolor.h" + + +static GeglColor * gimp_color_parse_name_internal (const gchar *name); +static GeglColor * gimp_color_parse_hex_internal (const gchar *hex); +static GeglColor * gimp_color_parse_css_numeric (const gchar *css); +static GeglColor * gimp_color_parse_css_internal (const gchar *css); +static gchar * gimp_color_parse_strip (const gchar *str, + gint len); +static gint gimp_color_entry_compare (gconstpointer a, + gconstpointer b); +static gboolean gimp_color_parse_hex_component (const gchar *hex, + gint len, + gdouble *value); + + +typedef struct +{ + const gchar *name; + const guchar red; + const guchar green; + const guchar blue; +} ColorEntry; + +static const ColorEntry named_colors[] = +{ + { "aliceblue", 240, 248, 255 }, + { "antiquewhite", 250, 235, 215 }, + { "aqua", 0, 255, 255 }, + { "aquamarine", 127, 255, 212 }, + { "azure", 240, 255, 255 }, + { "beige", 245, 245, 220 }, + { "bisque", 255, 228, 196 }, + { "black", 0, 0, 0 }, + { "blanchedalmond", 255, 235, 205 }, + { "blue", 0, 0, 255 }, + { "blueviolet", 138, 43, 226 }, + { "brown", 165, 42, 42 }, + { "burlywood", 222, 184, 135 }, + { "cadetblue", 95, 158, 160 }, + { "chartreuse", 127, 255, 0 }, + { "chocolate", 210, 105, 30 }, + { "coral", 255, 127, 80 }, + { "cornflowerblue", 100, 149, 237 }, + { "cornsilk", 255, 248, 220 }, + { "crimson", 220, 20, 60 }, + { "cyan", 0, 255, 255 }, + { "darkblue", 0, 0, 139 }, + { "darkcyan", 0, 139, 139 }, + { "darkgoldenrod", 184, 134, 11 }, + { "darkgray", 169, 169, 169 }, + { "darkgreen", 0, 100, 0 }, + { "darkgrey", 169, 169, 169 }, + { "darkkhaki", 189, 183, 107 }, + { "darkmagenta", 139, 0, 139 }, + { "darkolivegreen", 85, 107, 47 }, + { "darkorange", 255, 140, 0 }, + { "darkorchid", 153, 50, 204 }, + { "darkred", 139, 0, 0 }, + { "darksalmon", 233, 150, 122 }, + { "darkseagreen", 143, 188, 143 }, + { "darkslateblue", 72, 61, 139 }, + { "darkslategray", 47, 79, 79 }, + { "darkslategrey", 47, 79, 79 }, + { "darkturquoise", 0, 206, 209 }, + { "darkviolet", 148, 0, 211 }, + { "deeppink", 255, 20, 147 }, + { "deepskyblue", 0, 191, 255 }, + { "dimgray", 105, 105, 105 }, + { "dimgrey", 105, 105, 105 }, + { "dodgerblue", 30, 144, 255 }, + { "firebrick", 178, 34, 34 }, + { "floralwhite" , 255, 250, 240 }, + { "forestgreen", 34, 139, 34 }, + { "fuchsia", 255, 0, 255 }, + { "gainsboro", 220, 220, 220 }, + { "ghostwhite", 248, 248, 255 }, + { "gold", 255, 215, 0 }, + { "goldenrod", 218, 165, 32 }, + { "gray", 128, 128, 128 }, + { "green", 0, 128, 0 }, + { "greenyellow", 173, 255, 47 }, + { "grey", 128, 128, 128 }, + { "honeydew", 240, 255, 240 }, + { "hotpink", 255, 105, 180 }, + { "indianred", 205, 92, 92 }, + { "indigo", 75, 0, 130 }, + { "ivory", 255, 255, 240 }, + { "khaki", 240, 230, 140 }, + { "lavender", 230, 230, 250 }, + { "lavenderblush", 255, 240, 245 }, + { "lawngreen", 124, 252, 0 }, + { "lemonchiffon", 255, 250, 205 }, + { "lightblue", 173, 216, 230 }, + { "lightcoral", 240, 128, 128 }, + { "lightcyan", 224, 255, 255 }, + { "lightgoldenrodyellow", 250, 250, 210 }, + { "lightgray", 211, 211, 211 }, + { "lightgreen", 144, 238, 144 }, + { "lightgrey", 211, 211, 211 }, + { "lightpink", 255, 182, 193 }, + { "lightsalmon", 255, 160, 122 }, + { "lightseagreen", 32, 178, 170 }, + { "lightskyblue", 135, 206, 250 }, + { "lightslategray", 119, 136, 153 }, + { "lightslategrey", 119, 136, 153 }, + { "lightsteelblue", 176, 196, 222 }, + { "lightyellow", 255, 255, 224 }, + { "lime", 0, 255, 0 }, + { "limegreen", 50, 205, 50 }, + { "linen", 250, 240, 230 }, + { "magenta", 255, 0, 255 }, + { "maroon", 128, 0, 0 }, + { "mediumaquamarine", 102, 205, 170 }, + { "mediumblue", 0, 0, 205 }, + { "mediumorchid", 186, 85, 211 }, + { "mediumpurple", 147, 112, 219 }, + { "mediumseagreen", 60, 179, 113 }, + { "mediumslateblue", 123, 104, 238 }, + { "mediumspringgreen", 0, 250, 154 }, + { "mediumturquoise", 72, 209, 204 }, + { "mediumvioletred", 199, 21, 133 }, + { "midnightblue", 25, 25, 112 }, + { "mintcream", 245, 255, 250 }, + { "mistyrose", 255, 228, 225 }, + { "moccasin", 255, 228, 181 }, + { "navajowhite", 255, 222, 173 }, + { "navy", 0, 0, 128 }, + { "oldlace", 253, 245, 230 }, + { "olive", 128, 128, 0 }, + { "olivedrab", 107, 142, 35 }, + { "orange", 255, 165, 0 }, + { "orangered", 255, 69, 0 }, + { "orchid", 218, 112, 214 }, + { "palegoldenrod", 238, 232, 170 }, + { "palegreen", 152, 251, 152 }, + { "paleturquoise", 175, 238, 238 }, + { "palevioletred", 219, 112, 147 }, + { "papayawhip", 255, 239, 213 }, + { "peachpuff", 255, 218, 185 }, + { "peru", 205, 133, 63 }, + { "pink", 255, 192, 203 }, + { "plum", 221, 160, 221 }, + { "powderblue", 176, 224, 230 }, + { "purple", 128, 0, 128 }, + { "red", 255, 0, 0 }, + { "rosybrown", 188, 143, 143 }, + { "royalblue", 65, 105, 225 }, + { "saddlebrown", 139, 69, 19 }, + { "salmon", 250, 128, 114 }, + { "sandybrown", 244, 164, 96 }, + { "seagreen", 46, 139, 87 }, + { "seashell", 255, 245, 238 }, + { "sienna", 160, 82, 45 }, + { "silver", 192, 192, 192 }, + { "skyblue", 135, 206, 235 }, + { "slateblue", 106, 90, 205 }, + { "slategray", 112, 128, 144 }, + { "slategrey", 112, 128, 144 }, + { "snow", 255, 250, 250 }, + { "springgreen", 0, 255, 127 }, + { "steelblue", 70, 130, 180 }, + { "tan", 210, 180, 140 }, + { "teal", 0, 128, 128 }, + { "thistle", 216, 191, 216 }, + { "tomato", 255, 99, 71 }, + { "turquoise", 64, 224, 208 }, + { "violet", 238, 130, 238 }, + { "wheat", 245, 222, 179 }, + { "white", 255, 255, 255 }, + { "whitesmoke", 245, 245, 245 }, + { "yellow", 255, 255, 0 }, + { "yellowgreen", 154, 205, 50 } +}; + + +/** + * gimp_color_parse_css: + * @css: (array length=len): a string describing a color in CSS notation + * @len: the length of @css, in bytes. or -1 if @css is nul-terminated + * + * Attempts to parse a string describing an sRGB color in CSS notation. This can + * be either a numerical representation (`rgb(255,0,0)` or `rgb(100%,0%,0%)`) + * or a hexadecimal notation as parsed by gimp_color_parse_hex() + * (`##ff0000`) or a color name as parsed by gimp_color_parse_name() (`red`). + * + * Additionally the `rgba()`, `hsl()` and `hsla()` functions are supported too. + * + * Returns: a newly allocated [class@Gegl.Color] if @css was parsed successfully + * %NULL otherwise + * + * Since: 2.2 + **/ +GeglColor * +gimp_color_parse_css (const gchar *css, + gint len) +{ + gchar *tmp; + GeglColor *color; + + g_return_val_if_fail (css != NULL, FALSE); + + tmp = gimp_color_parse_strip (css, len); + + color = gimp_color_parse_css_internal (tmp); + + g_free (tmp); + + return color; +} + + +/* Private functions. */ + +static GeglColor * +gimp_color_parse_name_internal (const gchar *name) +{ + /* GeglColor also has name reading support. It supports HTML 4.01 standard + * whereas here we have SVG 1.0 name support. Moreover we support a lot more + * colors. + */ + ColorEntry *entry = bsearch (name, named_colors, + G_N_ELEMENTS (named_colors), sizeof (ColorEntry), + gimp_color_entry_compare); + + if (entry) + { + GeglColor *color = gegl_color_new (NULL); + + gegl_color_set_rgba_with_space (color, (gdouble) entry->red / 255.0, + (gdouble) entry->green / 255.0, (gdouble) entry->blue / 255.0, + 1.0, NULL); + + return color; + } + + return NULL; +} + +static GeglColor * +gimp_color_parse_hex_internal (const gchar *hex) +{ + GeglColor *color; + gint i; + gsize len; + gdouble val[3]; + + if (hex[0] == '#') + hex++; + + len = strlen (hex); + if (len % 3 || len < 3 || len > 12) + return NULL; + + len /= 3; + + for (i = 0; i < 3; i++, hex += len) + { + if (! gimp_color_parse_hex_component (hex, len, val + i)) + return NULL; + } + + color = gegl_color_new (NULL); + gegl_color_set_pixel (color, babl_format ("R'G'B' double"), val); + + return color; +} + +static GeglColor * +gimp_color_parse_css_numeric (const gchar *css) +{ + GeglColor *color; + gdouble values[4]; + gboolean alpha; + gboolean hsl; + gint i; + + if (css[0] == 'r' && css[1] == 'g' && css[2] == 'b') + hsl = FALSE; + else if (css[0] == 'h' && css[1] == 's' && css[2] == 'l') + hsl = TRUE; + else + g_return_val_if_reached (NULL); + + if (css[3] == 'a' && css[4] == '(') + alpha = TRUE; + else if (css[3] == '(') + alpha = FALSE; + else + g_return_val_if_reached (NULL); + + css += (alpha ? 5 : 4); + + for (i = 0; i < (alpha ? 4 : 3); i++) + { + const gchar *end = css; + + while (*end && *end != ',' && *end != '%' && *end != ')') + end++; + + if (i == 3 || *end == '%') + { + values[i] = g_ascii_strtod (css, (gchar **) &end); + + if (errno == ERANGE) + return FALSE; + + if (*end == '%') + { + end++; + values[i] /= 100.0; + } + } + else + { + glong value = strtol (css, (gchar **) &end, 10); + + if (errno == ERANGE) + return FALSE; + + if (hsl) + values[i] = value / (i == 0 ? 360.0 : 100.0); + else + values[i] = value / 255.0; + } + + /* CSS Color specs indicates: + * > Values outside these ranges are not invalid, but are clamped to the + * > ranges defined here at parsed-value time. + * See: https://drafts.csswg.org/css-color/#rgb-functions + * So even though we might hope being able to reach non-sRGB colors when + * using the percentage syntax, the spec explicitly forbids it. + */ + values[i] = CLAMP (values[i], 0.0, 1.0); + + while (*end == ',' || g_ascii_isspace (*end)) + end++; + + css = end; + } + + if (*css != ')') + return NULL; + + color = gegl_color_new (NULL); + if (hsl) + { + if (alpha) + gegl_color_set_pixel (color, babl_format ("HSLA double"), values); + else + gegl_color_set_pixel (color, babl_format ("HSL double"), values); + } + else + { + if (alpha) + gegl_color_set_pixel (color, babl_format ("R'G'B'A double"), values); + else + gegl_color_set_pixel (color, babl_format ("R'G'B' double"), values); + } + + return color; +} + +static GeglColor * +gimp_color_parse_css_internal (const gchar *css) +{ + if (css[0] == '#') + { + return gimp_color_parse_hex_internal (css); + } + else if (strncmp (css, "rgb(", 4) == 0 || + strncmp (css, "hsl(", 4) == 0) + { + return gimp_color_parse_css_numeric (css); + } + else + { + return gimp_color_parse_name_internal (css); + } +} + +static gchar * +gimp_color_parse_strip (const gchar *str, + gint len) +{ + gchar *result; + + while (len > 0 && g_ascii_isspace (*str)) + { + str++; + len--; + } + + if (len < 0) + { + while (g_ascii_isspace (*str)) + str++; + + len = strlen (str); + } + + while (len > 0 && g_ascii_isspace (str[len - 1])) + len--; + + result = g_malloc (len + 1); + + memcpy (result, str, len); + result[len] = '\0'; + + return result; +} + +static gint +gimp_color_entry_compare (gconstpointer a, + gconstpointer b) +{ + const gchar *name = a; + const ColorEntry *entry = b; + + return g_ascii_strcasecmp (name, entry->name); +} + +static gboolean +gimp_color_parse_hex_component (const gchar *hex, + gint len, + gdouble *value) +{ + gint i; + guint c = 0; + + for (i = 0; i < len; i++, hex++) + { + if (!*hex || !g_ascii_isxdigit (*hex)) + return FALSE; + + c = (c << 4) | g_ascii_xdigit_value (*hex); + } + + switch (len) + { + case 1: *value = (gdouble) c / 15.0; break; + case 2: *value = (gdouble) c / 255.0; break; + case 3: *value = (gdouble) c / 4095.0; break; + case 4: *value = (gdouble) c / 65535.0; break; + default: + g_return_val_if_reached (FALSE); + } + + return TRUE; +} diff --git a/libgimpcolor/gimpcolor.c b/libgimpcolor/gimpcolor.c index 0bbc71f722..5d8b5be2ca 100644 --- a/libgimpcolor/gimpcolor.c +++ b/libgimpcolor/gimpcolor.c @@ -39,6 +39,10 @@ * objects more easily. **/ + +static const Babl * gimp_babl_format_get_with_alpha (const Babl *format); + + /** * gimp_color_set_alpha: * @color: a [class@Gegl.Color] @@ -79,6 +83,7 @@ gimp_color_set_alpha (GeglColor *color, * Let's assume that since we use an unbounded 32-bit intermediate value * (float), the loss would be acceptable. */ + format = gimp_babl_format_get_with_alpha (format); gegl_color_get_pixel (color, format, pixel); gegl_color_set_pixel (color, format, pixel); } @@ -138,3 +143,62 @@ gimp_color_is_perceptually_identical (GeglColor *color1, SQR (pixel1[2] - pixel2[2]) <= 1e-4)); #undef SQR } + + +/* Private functions. */ + +static const Babl * +gimp_babl_format_get_with_alpha (const Babl *format) +{ + const Babl *new_format = NULL; + const gchar *new_model = NULL; + const gchar *model; + const gchar *type; + gchar *name; + + if (babl_format_has_alpha (format)) + return format; + + model = babl_get_name (babl_format_get_model (format)); + /* Assuming we use Babl formats with same type for all components. */ + type = babl_get_name (babl_format_get_type (format, 0)); + + if (g_strcmp0 (model, "Y") == 0) + new_model = "YA"; + else if (g_strcmp0 (model, "RGB") == 0) + new_model = "RGBA"; + else if (g_strcmp0 (model, "Y'") == 0) + new_model = "Y'A"; + else if (g_strcmp0 (model, "R'G'B'") == 0) + new_model = "R'G'B'A"; + else if (g_strcmp0 (model, "Y~") == 0) + new_model = "Y~A"; + else if (g_strcmp0 (model, "R~G~B~") == 0) + new_model = "R~G~B~A"; + else if (g_strcmp0 (model, "CIE Lab") == 0) + new_model = "CIE Lab alpha"; + else if (g_strcmp0 (model, "CIE xyY") == 0) + new_model = "CIE xyY alpha"; + else if (g_strcmp0 (model, "CIE XYZ") == 0) + new_model = "CIE XYZ alpha"; + else if (g_strcmp0 (model, "CIE Yuv") == 0) + new_model = "CIE Yuv alpha"; + else if (g_strcmp0 (model, "CMYK") == 0) + new_model = "CMYKA"; + else if (g_strcmp0 (model, "cmyk") == 0) + new_model = "cmykA"; + else if (g_strcmp0 (model, "HSL") == 0) + new_model = "HSLA"; + else if (g_strcmp0 (model, "HSV") == 0) + new_model = "HSVA"; + else if (g_strcmp0 (model, "cairo-RGB24") == 0) + new_model = "cairo-ARGB32"; + + g_return_val_if_fail (new_model != NULL, format); + + name = g_strdup_printf ("%s %s", new_model, type); + new_format = babl_format_with_space (name, format); + g_free (name); + + return new_format; +} diff --git a/libgimpcolor/gimpcolor.def b/libgimpcolor/gimpcolor.def index 7390e740f3..e3a2f54c7b 100644 --- a/libgimpcolor/gimpcolor.def +++ b/libgimpcolor/gimpcolor.def @@ -30,6 +30,7 @@ EXPORTS gimp_color_managed_simulation_bpc_changed gimp_color_managed_simulation_intent_changed gimp_color_managed_simulation_profile_changed + gimp_color_parse_css gimp_color_profile_get_copyright gimp_color_profile_get_description gimp_color_profile_get_format diff --git a/libgimpcolor/gimpcolor.h b/libgimpcolor/gimpcolor.h index d4aa629790..c0a52ad8de 100644 --- a/libgimpcolor/gimpcolor.h +++ b/libgimpcolor/gimpcolor.h @@ -47,11 +47,14 @@ G_BEGIN_DECLS #define GIMP_VALUE_HOLDS_COLOR(value) (G_TYPE_CHECK_VALUE_TYPE ((value), GEGL_TYPE_COLOR)) -void gimp_color_set_alpha (GeglColor *color, - gdouble alpha); +void gimp_color_set_alpha (GeglColor *color, + gdouble alpha); -gboolean gimp_color_is_perceptually_identical (GeglColor *color1, - GeglColor *color2); +gboolean gimp_color_is_perceptually_identical (GeglColor *color1, + GeglColor *color2); + +GeglColor * gimp_color_parse_css (const gchar *css, + gint len); G_END_DECLS diff --git a/libgimpcolor/meson.build b/libgimpcolor/meson.build index a4aefe051e..d578ec33ed 100644 --- a/libgimpcolor/meson.build +++ b/libgimpcolor/meson.build @@ -5,6 +5,7 @@ libgimpcolor_sources = files( 'gimpcairo.c', 'gimpcmyk.c', 'gimpcolor.c', + 'gimpcolor-parse.c', 'gimpcolormanaged.c', 'gimpcolorprofile.c', 'gimpcolorspace.c', diff --git a/pdb/groups/gradient.pdb b/pdb/groups/gradient.pdb index cc75d3529b..dcc0da5647 100644 --- a/pdb/groups/gradient.pdb +++ b/pdb/groups/gradient.pdb @@ -168,23 +168,27 @@ HELP num_color_samples = num_samples * 4; - sample = color_samples = g_new (gdouble, num_color_samples); + sample = color_samples = g_new0 (gdouble, num_color_samples); while (num_samples--) { - GimpRGB color; + GeglColor *color = NULL; seg = gimp_gradient_get_color_at (gradient, context, seg, pos, reverse, GIMP_GRADIENT_BLEND_RGB_PERCEPTUAL, &color); + /* XXX "float" in PDB are in fact double. */ + if (color) + gegl_color_get_pixel (color, babl_format ("R'G'B'A double"), sample); + /* TODO: should we really return a list of floats? What about a list + * of GeglColor? + */ - *sample++ = color.r; - *sample++ = color.g; - *sample++ = color.b; - *sample++ = color.a; + sample += 4; + pos += delta; - pos += delta; + g_clear_object (&color); } } else @@ -233,11 +237,11 @@ HELP num_color_samples = num_samples * 4; - sample = color_samples = g_new (gdouble, num_color_samples); + sample = color_samples = g_new0 (gdouble, num_color_samples); while (num_samples--) { - GimpRGB color; + GeglColor *color = NULL; seg = gimp_gradient_get_color_at (gradient, context, seg, *positions, @@ -245,12 +249,13 @@ HELP GIMP_GRADIENT_BLEND_RGB_PERCEPTUAL, &color); - *sample++ = color.r; - *sample++ = color.g; - *sample++ = color.b; - *sample++ = color.a; + if (color) + gegl_color_get_pixel (color, babl_format ("R'G'B'A double"), sample); + sample += 4; positions++; + + g_clear_object (&color); } } else @@ -277,10 +282,8 @@ HELP ); @outargs = ( - { name => 'color', type => 'color', void_ret => 1, + { name => 'color', type => 'geglcolor', desc => 'The return color' }, - { name => 'opacity', type => 'float', - desc => 'The opacity of the endpoint' } ); %invoke = ( @@ -291,10 +294,7 @@ HELP seg = gimp_gradient_segment_get_nth (gradient->segments, segment); if (seg) - { - gimp_gradient_segment_get_left_color (gradient, seg, &color); - opacity = color.a * 100.0; - } + color = g_object_ref (gimp_gradient_segment_get_left_color (gradient, seg)); else success = FALSE; } @@ -318,10 +318,8 @@ HELP ); @outargs = ( - { name => 'color', type => 'color', void_ret => 1, - desc => 'The return color' }, - { name => 'opacity', type => 'float', - desc => 'The opacity of the endpoint' } + { name => 'color', type => 'geglcolor', + desc => 'The return color' } ); %invoke = ( @@ -332,10 +330,7 @@ HELP seg = gimp_gradient_segment_get_nth (gradient->segments, segment); if (seg) - { - gimp_gradient_segment_get_right_color (gradient, seg, &color); - opacity = color.a * 100.0; - } + color = g_object_ref (gimp_gradient_segment_get_right_color (gradient, seg)); else success = FALSE; } @@ -346,7 +341,8 @@ CODE sub gradient_segment_set_left_color { $blurb = 'Sets the left endpoint color of a segment'; $help = <<'HELP'; -Sets the color of the left endpoint the indexed segment of the gradient. +Sets the color of the left endpoint the indexed segment of the gradient. The +alpha channel of the [class@Gegl.Color] is taken into account. Returns an error when gradient is not editable or index is out of range. HELP @@ -356,10 +352,7 @@ HELP @inargs = ( ${gradient_arg_spec}, ${gradient_seg_arg_spec}, - { name => 'color', type => 'color', - desc => 'The color to set' }, - { name => 'opacity', type => '0 <= float <= 100.0', - desc => 'The opacity to set for the endpoint' } + { name => 'color', type => 'geglcolor', desc => 'The color to set' } ); %invoke = ( @@ -367,18 +360,13 @@ HELP { if (gimp_data_is_writable (GIMP_DATA (gradient))) { - GimpGradientSegment *seg = gimp_gradient_segment_get_nth (gradient->segments, segment); + GimpGradientSegment *seg = gimp_gradient_segment_get_nth (gradient->segments, segment); - if (seg) - { - color.a = opacity / 100.0; - gimp_gradient_segment_set_left_color (gradient, seg, &color); - } - else - { + if (seg) + gimp_gradient_segment_set_left_color (gradient, seg, color); + else success = FALSE; } - } else { success = FALSE; @@ -392,7 +380,8 @@ sub gradient_segment_set_right_color { $blurb = 'Sets the right endpoint color of the segment'; $help = <<'HELP'; -Sets the right endpoint color of the segment of the gradient. +Sets the right endpoint color of the segment of the gradient. The alpha channel +of the [class@Gegl.Color] is taken into account. Returns an error when gradient is not editable or segment index is out of range. HELP @@ -402,10 +391,7 @@ HELP @inargs = ( ${gradient_arg_spec}, ${gradient_seg_arg_spec}, - { name => 'color', type => 'color', - desc => 'The color to set' }, - { name => 'opacity', type => '0 <= float <= 100.0', - desc => 'The opacity to set for the endpoint' } + { name => 'color', type => 'geglcolor', desc => 'The color to set' } ); %invoke = ( @@ -416,10 +402,7 @@ HELP GimpGradientSegment *seg = gimp_gradient_segment_get_nth (gradient->segments, segment); if (seg) - { - color.a = opacity / 100.0; - gimp_gradient_segment_set_right_color (gradient, seg, &color); - } + gimp_gradient_segment_set_right_color (gradient, seg, color); else success = FALSE; } @@ -1129,8 +1112,8 @@ HELP if (start_seg && end_seg) gimp_gradient_segment_range_blend (gradient, start_seg, end_seg, - &start_seg->left_color, - &end_seg->right_color, + start_seg->left_color, + end_seg->right_color, TRUE, FALSE); else success = FALSE; @@ -1176,8 +1159,8 @@ HELP if (start_seg && end_seg) gimp_gradient_segment_range_blend (gradient, start_seg, end_seg, - &start_seg->left_color, - &end_seg->right_color, + start_seg->left_color, + end_seg->right_color, FALSE, TRUE); else success = FALSE;