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;