diff --git a/app/core/gimpimage-colormap.c b/app/core/gimpimage-colormap.c index 57a5604570..57b4aa8f4a 100644 --- a/app/core/gimpimage-colormap.c +++ b/app/core/gimpimage-colormap.c @@ -254,12 +254,11 @@ _gimp_image_get_colormap (GimpImage *image, gint *n_colors) { GimpImagePrivate *private; - guchar *colormap = NULL; const Babl *space; const Babl *format; - gint bpp; g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL); + private = GIMP_IMAGE_GET_PRIVATE (image); if (private->palette == NULL) @@ -267,23 +266,8 @@ _gimp_image_get_colormap (GimpImage *image, space = gimp_image_get_layer_space (image); format = gimp_babl_format (GIMP_RGB, private->precision, FALSE, space); - bpp = babl_format_get_bytes_per_pixel (format); - *n_colors = gimp_palette_get_n_colors (private->palette); - - if (*n_colors > 0) - { - colormap = g_new0 (guchar, GIMP_IMAGE_COLORMAP_SIZE); - - for (gint i = 0; i < *n_colors; i++) - { - GimpPaletteEntry *entry = gimp_palette_get_entry (private->palette, i); - - gegl_color_get_pixel (entry->color, format, &colormap[i * bpp]); - } - } - - return colormap; + return gimp_palette_get_colormap (private->palette, format, n_colors); } void diff --git a/app/core/gimppalette.c b/app/core/gimppalette.c index 2bf91a9ab4..74535b34e7 100644 --- a/app/core/gimppalette.c +++ b/app/core/gimppalette.c @@ -764,6 +764,41 @@ gimp_palette_find_entry (GimpPalette *palette, return NULL; } +guchar * +gimp_palette_get_colormap (GimpPalette *palette, + const Babl *format, + gint *n_colors) +{ + guchar *colormap = NULL; + gint bpp; + + g_return_val_if_fail (GIMP_IS_PALETTE (palette), NULL); + g_return_val_if_fail (format != NULL, NULL); + g_return_val_if_fail (n_colors != NULL, NULL); + + bpp = babl_format_get_bytes_per_pixel (format); + + *n_colors = gimp_palette_get_n_colors (palette); + + if (*n_colors > 0) + { + guchar *p; + + colormap = g_new0 (guchar, bpp * *n_colors); + p = colormap; + + for (gint i = 0; i < *n_colors; i++) + { + GimpPaletteEntry *entry = gimp_palette_get_entry (palette, i); + + gegl_color_get_pixel (entry->color, format, p); + p += bpp; + } + } + + return colormap; +} + /* private functions */ diff --git a/app/core/gimppalette.h b/app/core/gimppalette.h index e159ad89d8..06dc7ee8c5 100644 --- a/app/core/gimppalette.h +++ b/app/core/gimppalette.h @@ -111,5 +111,9 @@ GimpPaletteEntry * gimp_palette_find_entry (GimpPalette *palette, GeglColor *color, GimpPaletteEntry *start_from); +guchar * gimp_palette_get_colormap (GimpPalette *palette, + const Babl *format, + gint *n_colors); + #endif /* __GIMP_PALETTE_H__ */ diff --git a/app/pdb/internal-procs.c b/app/pdb/internal-procs.c index 8fdbe57831..bdb3648066 100644 --- a/app/pdb/internal-procs.c +++ b/app/pdb/internal-procs.c @@ -30,7 +30,7 @@ #include "internal-procs.h" -/* 778 procedures registered total */ +/* 779 procedures registered total */ void internal_procs_init (GimpPDB *pdb) diff --git a/app/pdb/palette-cmds.c b/app/pdb/palette-cmds.c index 2a4c87a182..3f93732602 100644 --- a/app/pdb/palette-cmds.c +++ b/app/pdb/palette-cmds.c @@ -453,6 +453,45 @@ palette_entry_set_name_invoker (GimpProcedure *procedure, error ? *error : NULL); } +static GimpValueArray * +palette_get_colormap_invoker (GimpProcedure *procedure, + Gimp *gimp, + GimpContext *context, + GimpProgress *progress, + const GimpValueArray *args, + GError **error) +{ + gboolean success = TRUE; + GimpValueArray *return_vals; + GimpPalette *palette; + const Babl *format; + GBytes *colormap = NULL; + gint num_colors = 0; + + palette = g_value_get_object (gimp_value_array_index (args, 0)); + format = g_value_get_boxed (gimp_value_array_index (args, 1)); + + if (success) + { + guchar *colormap_data; + gint bpp = babl_format_get_bytes_per_pixel (format); + + colormap_data = gimp_palette_get_colormap (palette, format, &num_colors); + colormap = g_bytes_new_take (colormap_data, bpp * num_colors); + } + + return_vals = gimp_procedure_get_return_values (procedure, success, + error ? *error : NULL); + + if (success) + { + g_value_take_boxed (gimp_value_array_index (return_vals, 1), colormap); + g_value_set_int (gimp_value_array_index (return_vals, 2), num_colors); + } + + return return_vals; +} + void register_palette_procs (GimpPDB *pdb) { @@ -874,4 +913,52 @@ register_palette_procs (GimpPDB *pdb) GIMP_PARAM_READWRITE)); gimp_pdb_register_procedure (pdb, procedure); g_object_unref (procedure); + + /* + * gimp-palette-get-colormap + */ + procedure = gimp_procedure_new (palette_get_colormap_invoker); + gimp_object_set_static_name (GIMP_OBJECT (procedure), + "gimp-palette-get-colormap"); + gimp_procedure_set_static_help (procedure, + "Returns the palette's colormap", + "This procedure returns an the image's colormap as a bytes array with all colors converted to a given Babl @format.\n" + "The byte-size of the returned colormap depends on the number of colors and on the bytes-per-pixel size of @format. E.g. that the following equality is ensured:\n" + "\n" + "```C\n" + "g_bytes_get_size (colormap) == num_colors * babl_format_get_bytes_per_pixel (format)\n" + "```", + NULL); + gimp_procedure_set_static_attribution (procedure, + "Jehan", + "Jehan", + "2024"); + gimp_procedure_add_argument (procedure, + gimp_param_spec_palette ("palette", + "palette", + "The palette", + FALSE, + NULL, + FALSE, + GIMP_PARAM_READWRITE)); + gimp_procedure_add_argument (procedure, + g_param_spec_boxed ("format", + "format", + "The desired color format", + GIMP_TYPE_BABL_FORMAT, + GIMP_PARAM_READWRITE)); + gimp_procedure_add_return_value (procedure, + g_param_spec_boxed ("colormap", + "colormap", + "The image's colormap.", + G_TYPE_BYTES, + GIMP_PARAM_READWRITE)); + gimp_procedure_add_return_value (procedure, + g_param_spec_int ("num-colors", + "num colors", + "The number of colors in the palette", + G_MININT32, G_MAXINT32, 0, + GIMP_PARAM_READWRITE)); + gimp_pdb_register_procedure (pdb, procedure); + g_object_unref (procedure); } diff --git a/libgimp/gimp.def b/libgimp/gimp.def index d83660a544..a932caba9e 100644 --- a/libgimp/gimp.def +++ b/libgimp/gimp.def @@ -669,6 +669,7 @@ EXPORTS gimp_palette_entry_set_name gimp_palette_get_by_name gimp_palette_get_color_count + gimp_palette_get_colormap gimp_palette_get_colors gimp_palette_get_columns gimp_palette_get_type diff --git a/libgimp/gimppalette_pdb.c b/libgimp/gimppalette_pdb.c index cd66053af0..a3d980e131 100644 --- a/libgimp/gimppalette_pdb.c +++ b/libgimp/gimppalette_pdb.c @@ -525,3 +525,56 @@ gimp_palette_entry_set_name (GimpPalette *palette, return success; } + +/** + * gimp_palette_get_colormap: + * @palette: The palette. + * @format: The desired color format. + * @num_colors: (out): The number of colors in the palette. + * + * Returns the palette's colormap + * + * This procedure returns an the image's colormap as a bytes array with + * all colors converted to a given Babl @format. + * The byte-size of the returned colormap depends on the number of + * colors and on the bytes-per-pixel size of @format. E.g. that the + * following equality is ensured: + * + * ```C + * g_bytes_get_size (colormap) == num_colors * + * babl_format_get_bytes_per_pixel (format) + * ``` + * + * Returns: (transfer full): The image's colormap. + * + * Since: 3.0 + **/ +GBytes * +gimp_palette_get_colormap (GimpPalette *palette, + const Babl *format, + gint *num_colors) +{ + GimpValueArray *args; + GimpValueArray *return_vals; + GBytes *colormap = NULL; + + args = gimp_value_array_new_from_types (NULL, + GIMP_TYPE_PALETTE, palette, + GIMP_TYPE_BABL_FORMAT, format, + G_TYPE_NONE); + + return_vals = _gimp_pdb_run_procedure_array (gimp_get_pdb (), + "gimp-palette-get-colormap", + args); + gimp_value_array_unref (args); + + if (GIMP_VALUES_GET_ENUM (return_vals, 0) == GIMP_PDB_SUCCESS) + { + colormap = GIMP_VALUES_DUP_BYTES (return_vals, 1); + *num_colors = GIMP_VALUES_GET_INT (return_vals, 2); + } + + gimp_value_array_unref (return_vals); + + return colormap; +} diff --git a/libgimp/gimppalette_pdb.h b/libgimp/gimppalette_pdb.h index 8ac5777486..f6dc3a8e6d 100644 --- a/libgimp/gimppalette_pdb.h +++ b/libgimp/gimppalette_pdb.h @@ -56,6 +56,9 @@ gboolean gimp_palette_entry_get_name (GimpPalette *palette, gboolean gimp_palette_entry_set_name (GimpPalette *palette, gint entry_num, const gchar *entry_name); +GBytes* gimp_palette_get_colormap (GimpPalette *palette, + const Babl *format, + gint *num_colors); G_END_DECLS diff --git a/libgimp/tests/test-palette.c b/libgimp/tests/test-palette.c index 803f8ec399..08c06dce16 100644 --- a/libgimp/tests/test-palette.c +++ b/libgimp/tests/test-palette.c @@ -19,9 +19,17 @@ gimp_c_test_run (GimpProcedure *procedure, GimpPalette *palette2; GeglColor **colors; gint n_colors; + GBytes *colormap; + const guchar *u8_data; + const gfloat *float_data; + gint n_colormap_colors; const Babl *format; + const Babl *format2; + gint format_bpp; + gint format2_bpp; GeglColor *color; guint8 rgb[3]; + gfloat rgba[4]; GimpValueArray *retvals; GIMP_TEST_START("gimp_palette_get_by_name()") @@ -49,6 +57,38 @@ gimp_c_test_run (GimpProcedure *procedure, gegl_color_get_pixel (color, format, rgb); GIMP_TEST_END(rgb[0] == GIMP_TEST_COLOR_R_U8 && rgb[1] == GIMP_TEST_COLOR_G_U8 && rgb[2] == GIMP_TEST_COLOR_B_U8) + GIMP_TEST_START("gimp_palette_get_colormap()") + colormap = gimp_palette_get_colormap (palette, format, &n_colormap_colors); + format_bpp = babl_format_get_bytes_per_pixel (format); + GIMP_TEST_END(colormap != NULL && n_colormap_colors == n_colors && + n_colormap_colors * format_bpp == g_bytes_get_size (colormap)) + + GIMP_TEST_START("Comparing fourth palette color's RGB components from colormap") + u8_data = g_bytes_get_data (colormap, NULL); + GIMP_TEST_END(u8_data[format_bpp * GIMP_TEST_COLOR_IDX] == GIMP_TEST_COLOR_R_U8 && + u8_data[format_bpp * GIMP_TEST_COLOR_IDX + 1] == GIMP_TEST_COLOR_G_U8 && + u8_data[format_bpp * GIMP_TEST_COLOR_IDX + 2]== GIMP_TEST_COLOR_B_U8) + + g_bytes_unref (colormap); + + GIMP_TEST_START("gimp_palette_get_colormap() in \"R'G'B'A float\" format") + format2 = babl_format ("RGBA float"); + format2_bpp = babl_format_get_bytes_per_pixel (format2); + colormap = gimp_palette_get_colormap (palette, format2, &n_colormap_colors); + GIMP_TEST_END(colormap != NULL && n_colormap_colors == n_colors && + format2 != format && + format2_bpp > format_bpp && + n_colormap_colors * format2_bpp == g_bytes_get_size (colormap)) + + GIMP_TEST_START("Comparing fourth palette color's RGB components from colormap in float format") + gegl_color_get_pixel (color, format2, rgba); + float_data = g_bytes_get_data (colormap, NULL); + GIMP_TEST_END(float_data[4 * GIMP_TEST_COLOR_IDX] == rgba[0] && + float_data[4 * GIMP_TEST_COLOR_IDX + 1] == rgba[1] && + float_data[4 * GIMP_TEST_COLOR_IDX + 2]== rgba[2]) + + g_bytes_unref (colormap); + /* Run the same tests through PDB. */ GIMP_TEST_START("gimp-palette-get-by-name") diff --git a/libgimp/tests/test-palette.py b/libgimp/tests/test-palette.py index 47a4b65b82..0dc6d11ac3 100644 --- a/libgimp/tests/test-palette.py +++ b/libgimp/tests/test-palette.py @@ -1,5 +1,7 @@ #!/usr/bin/env python3 +import struct + GIMP_TEST_PALETTE = "Bears" GIMP_TEST_PALETTE_SIZE = 256 GIMP_TEST_COLOR_IDX = 3 @@ -22,13 +24,49 @@ gimp_assert('gimp_palette_get_colors()', len(colors) == GIMP_TEST_PALETTE_SIZE and type(colors[0]) == Gegl.Color) f = colors[GIMP_TEST_COLOR_IDX].get_format() -gimp_assert ("Checking fourth palette color's format", - f == Babl.format (GIMP_TEST_COLOR_FORMAT)) +gimp_assert("Checking fourth palette color's format", + f == Babl.format (GIMP_TEST_COLOR_FORMAT)) b = colors[GIMP_TEST_COLOR_IDX].get_bytes(f) rgb = b.get_data() -gimp_assert ("Checking fourth palette color's RGB components", - int(rgb[0]) == GIMP_TEST_COLOR_R_U8 and int(rgb[1]) == GIMP_TEST_COLOR_G_U8 and int(rgb[2]) == GIMP_TEST_COLOR_B_U8) +gimp_assert("Checking fourth palette color's RGB components", + int(rgb[0]) == GIMP_TEST_COLOR_R_U8 and int(rgb[1]) == GIMP_TEST_COLOR_G_U8 and int(rgb[2]) == GIMP_TEST_COLOR_B_U8) + +colormap, n_colormap_colors = pal.get_colormap (f) +format_bpp = Babl.format_get_bytes_per_pixel (f); +gimp_assert("gimp_palette_get_colormap()", + colormap is not None and n_colormap_colors == n_colors and + n_colormap_colors * format_bpp == colormap.get_size()) + +u8_data = colormap.get_data () +gimp_assert("Comparing fourth palette color's RGB components from colormap", + u8_data[format_bpp * GIMP_TEST_COLOR_IDX] == GIMP_TEST_COLOR_R_U8 and + u8_data[format_bpp * GIMP_TEST_COLOR_IDX + 1] == GIMP_TEST_COLOR_G_U8 and + u8_data[format_bpp * GIMP_TEST_COLOR_IDX + 2]== GIMP_TEST_COLOR_B_U8) + +f2 = Babl.format('RGBA float') +colormap, n_colormap_colors = pal.get_colormap (f2) +f2_bpp = Babl.format_get_bytes_per_pixel (f2); +gimp_assert('gimp_palette_get_colormap() in "RGBA float"', + colormap is not None and n_colormap_colors == n_colors and + n_colormap_colors * f2_bpp == colormap.get_size()) + + +u8_data = colormap.get_data () +start = f2_bpp * GIMP_TEST_COLOR_IDX +colormap_r = struct.unpack('f', u8_data[start:start + 4]) +colormap_g = struct.unpack('f', u8_data[start + 4:start + 8]) +colormap_b = struct.unpack('f', u8_data[start + 8:start + 12]) + +rgb_bytes = colors[GIMP_TEST_COLOR_IDX].get_bytes(f2) +rgb = rgb_bytes.get_data() +palette_r = struct.unpack('f', rgb[:4]) +palette_g = struct.unpack('f', rgb[4:8]) +palette_b = struct.unpack('f', rgb[8:12]) +gimp_assert("Comparing fourth palette color's RGB components from colormap in float format", + colormap_r == palette_r and + colormap_g == palette_g and + colormap_b == palette_b) # Run the same tests through PDB: diff --git a/pdb/groups/palette.pdb b/pdb/groups/palette.pdb index bbdd45971e..99754cb1f9 100644 --- a/pdb/groups/palette.pdb +++ b/pdb/groups/palette.pdb @@ -430,6 +430,50 @@ CODE ); } +sub palette_get_colormap { + $blurb = "Returns the palette's colormap"; + + $help = <<'HELP'; +This procedure returns an the image's colormap as a bytes array with all +colors converted to a given Babl @format. + +The byte-size of the returned colormap depends on the number of colors +and on the bytes-per-pixel size of @format. E.g. that the following equality is ensured: + +```C +g_bytes_get_size (colormap) == num_colors * babl_format_get_bytes_per_pixel (format) +``` +HELP + + &jehan_pdb_misc('2024', '3.0'); + + @inargs = ( + { name => 'palette', type => 'palette', + desc => 'The palette' }, + { name => 'format', type => 'format', + desc => 'The desired color format' }, + ); + + @outargs = ( + { name => 'colormap', type => 'bytes', + desc => "The image's colormap." }, + { name => 'num_colors', type => 'int32', + desc => 'The number of colors in the palette' } + ); + + %invoke = ( + headers => [ qw("core/gimpimage-colormap.h") ], + code => <<'CODE' +{ + guchar *colormap_data; + gint bpp = babl_format_get_bytes_per_pixel (format); + + colormap_data = gimp_palette_get_colormap (palette, format, &num_colors); + colormap = g_bytes_new_take (colormap_data, bpp * num_colors); +} +CODE + ); +} @headers = qw( "core/gimp.h" @@ -446,7 +490,8 @@ CODE palette_get_columns palette_set_columns palette_add_entry palette_delete_entry palette_entry_get_color palette_entry_set_color - palette_entry_get_name palette_entry_set_name); + palette_entry_get_name palette_entry_set_name + palette_get_colormap); %exports = (app => [@procs], lib => [@procs]);