1
1
mirror of https://gitlab.gnome.org/GNOME/gimp.git synced 2025-10-06 05:22:40 +02:00

core: Add support for SwatchBooker palettes

This commit is contained in:
Alx Sa
2023-02-19 13:46:17 +00:00
parent 9e06e2aa53
commit 6597dabeb3
3 changed files with 409 additions and 2 deletions

View File

@@ -534,6 +534,10 @@ gimp_palette_import_from_file (GimpContext *context,
palette_list = gimp_palette_load_css (context, file, input, error);
break;
case GIMP_PALETTE_FILE_FORMAT_SBZ:
palette_list = gimp_palette_load_sbz (context, file, input, error);
break;
default:
g_set_error (error,
GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,

View File

@@ -19,21 +19,63 @@
#include <stdlib.h>
#include <archive.h>
#include <archive_entry.h>
#include <cairo.h>
#include <gegl.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gegl.h>
#include "libgimpbase/gimpbase.h"
#include "libgimpcolor/gimpcolor.h"
#include "core-types.h"
#include "config/gimpxmlparser.h"
#include "gimp-utils.h"
#include "gimppalette.h"
#include "gimppalette-load.h"
#include "gimp-intl.h"
typedef struct
{
GimpColorProfile *profile;
gchar *id;
} SwatchBookerColorProfile;
typedef struct
{
GimpPalette *palette;
gint position;
gchar *palette_name;
gchar *color_model;
gchar *color_space;
GList *embedded_profiles;
gboolean in_color_tag;
gboolean in_book_tag;
gboolean copy_name;
gboolean copy_values;
gint sorted_position;
} SwatchBookerData;
/* SwatchBooker XML parser functions */
static void swatchbooker_load_start_element (GMarkupParseContext *context,
const gchar *element_name,
const gchar **attribute_names,
const gchar **attribute_values,
gpointer user_data,
GError **error);
static void swatchbooker_load_end_element (GMarkupParseContext *context,
const gchar *element_name,
gpointer user_data,
GError **error);
static void swatchbooker_load_text (GMarkupParseContext *context,
const gchar *text,
gsize text_len,
gpointer user_data,
GError **error);
static gchar * gimp_palette_load_ase_block_name (GInputStream *input,
goffset file_size,
@@ -924,6 +966,358 @@ gimp_palette_load_css (GimpContext *context,
return g_list_prepend (NULL, palette);
}
GList *
gimp_palette_load_sbz (GimpContext *context,
GFile *file,
GInputStream *input,
GError **error)
{
SwatchBookerData sbz_data;
gchar *palette_name;
gchar *xml_data = NULL;
struct archive *a;
struct archive_entry *entry;
size_t entry_size;
int r;
g_return_val_if_fail (G_IS_FILE (file), NULL);
g_return_val_if_fail (G_IS_INPUT_STREAM (input), NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
palette_name = g_path_get_basename (gimp_file_get_utf8_name (file));
sbz_data.palette = GIMP_PALETTE (gimp_palette_new (context, palette_name));
g_free (palette_name);
sbz_data.position = 0;
sbz_data.sorted_position = 0;
sbz_data.in_color_tag = FALSE;
sbz_data.in_book_tag = FALSE;
sbz_data.copy_name = FALSE;
sbz_data.copy_values = FALSE;
sbz_data.embedded_profiles = NULL;
if ((a = archive_read_new ()))
{
const gchar *name = gimp_file_get_utf8_name (file);
archive_read_support_format_all (a);
r = archive_read_open_filename (a, name, 10240);
if (r != ARCHIVE_OK)
{
archive_read_free (a);
g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
_("Unable to read SBZ file"));
return NULL;
}
while (archive_read_next_header (a, &entry) == ARCHIVE_OK)
{
const gchar *lower = g_ascii_strdown (archive_entry_pathname (entry), -1);
if (g_str_has_suffix (lower, ".xml"))
{
entry_size = archive_entry_size (entry);
xml_data = (gchar *) g_malloc (entry_size);
r = archive_read_data (a, xml_data, entry_size);
}
else if (g_str_has_suffix (lower, ".icc") || g_str_has_suffix (lower, ".icm"))
{
GimpColorProfile *profile = NULL;
size_t icc_size = archive_entry_size (entry);
uint8_t *icc_data = g_malloc (icc_size);
r = archive_read_data (a, icc_data, icc_size);
if (icc_data)
profile = gimp_color_profile_new_from_icc_profile (icc_data, icc_size,
NULL);
if (profile)
{
SwatchBookerColorProfile sbz_profile;
sbz_profile.profile = profile;
sbz_profile.id = g_strdup (archive_entry_pathname (entry));
sbz_data.embedded_profiles =
g_list_append (sbz_data.embedded_profiles, &sbz_profile);
}
}
}
if (xml_data)
{
GimpXmlParser *xml_parser;
GMarkupParser markup_parser;
markup_parser.start_element = swatchbooker_load_start_element;
markup_parser.end_element = swatchbooker_load_end_element;
markup_parser.text = swatchbooker_load_text;
markup_parser.passthrough = NULL;
markup_parser.error = NULL;
xml_parser = gimp_xml_parser_new (&markup_parser, &sbz_data);
gimp_xml_parser_parse_buffer (xml_parser, xml_data, entry_size, NULL);
gimp_xml_parser_free (xml_parser);
g_free (xml_data);
}
r = archive_read_free (a);
}
else
{
g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
_("Unable to open SBZ file"));
return NULL;
}
return g_list_prepend (NULL, sbz_data.palette);
}
static void
swatchbooker_load_start_element (GMarkupParseContext *context,
const gchar *element_name,
const gchar **attribute_names,
const gchar **attribute_values,
gpointer user_data,
GError **error)
{
SwatchBookerData *sbz_data = user_data;
sbz_data->copy_values = FALSE;
sbz_data->color_model = NULL;
sbz_data->color_space = NULL;
if (! strcmp (g_ascii_strdown (element_name, -1), "color"))
{
sbz_data->in_color_tag = TRUE;
}
else if (! strcmp (g_ascii_strdown (element_name, -1), "dc:identifier"))
{
if (sbz_data->in_color_tag)
sbz_data->copy_name = TRUE;
}
else if (! strcmp (g_ascii_strdown (element_name, -1), "values"))
{
while (*attribute_names)
{
if (! strcmp (g_ascii_strdown (*attribute_names, -1), "model"))
{
sbz_data->color_model =
g_strdup (g_ascii_strdown (*attribute_values, -1));
}
else if (! strcmp (g_ascii_strdown (*attribute_names, -1), "space"))
{
sbz_data->color_space = g_strdup (*attribute_values);
}
attribute_names++;
attribute_values++;
}
sbz_data->copy_values = TRUE;
}
else if (! strcmp (g_ascii_strdown (element_name, -1), "book"))
{
sbz_data->in_book_tag = TRUE;
while (*attribute_names)
{
if (! strcmp (g_ascii_strdown (*attribute_names, -1), "columns"))
{
gint columns = atoi (*attribute_values);
if (columns > 0)
gimp_palette_set_columns (sbz_data->palette, columns);
break;
}
attribute_names++;
attribute_values++;
}
}
else if (! strcmp (g_ascii_strdown (element_name, -1), "swatch") &&
sbz_data->in_book_tag)
{
while (*attribute_names)
{
if (! strcmp (g_ascii_strdown (*attribute_names, -1), "material"))
{
GList *cols;
gint original_id = 0;
for (cols = gimp_palette_get_colors (sbz_data->palette);
cols;
cols = g_list_next (cols))
{
GimpPaletteEntry *entry = cols->data;
if (! strcmp (*attribute_values, entry->name))
{
gimp_palette_move_entry (sbz_data->palette, entry,
sbz_data->sorted_position);
sbz_data->sorted_position++;
break;
}
original_id++;
}
break;
}
attribute_names++;
attribute_values++;
}
}
}
static void
swatchbooker_load_end_element (GMarkupParseContext *context,
const gchar *element_name,
gpointer user_data,
GError **error)
{
SwatchBookerData *sbz_data = user_data;
if (! strcmp (g_ascii_strdown (element_name, -1), "color"))
sbz_data->in_color_tag = FALSE;
else if (! strcmp (g_ascii_strdown (element_name, -1), "book"))
sbz_data->in_book_tag = FALSE;
}
static void
swatchbooker_load_text (GMarkupParseContext *context,
const gchar *text,
gsize text_len,
gpointer user_data,
GError **error)
{
SwatchBookerData *sbz_data = user_data;
gchar **values;
gint i;
gint total = 0;
/* Save palette name */
if (sbz_data->copy_name)
{
if (! sbz_data->palette_name)
sbz_data->palette_name = g_strdup (text);
sbz_data->copy_name = FALSE;
}
/* Load palette entry */
if (sbz_data->copy_values)
{
values = g_strsplit (text, " ", 0);
for (i = 0; values[i]; i++)
total++;
if (total > 0)
{
gfloat true_values[total];
GimpRGB color;
gboolean load_pal = FALSE;
const Babl *src_format = NULL;
const Babl *dst_format = babl_format ("R'G'B' float");
const Babl *space = NULL;
/* Load profile if applicable */
if (sbz_data->embedded_profiles &&
sbz_data->color_space)
{
GList *profile_list;
for (profile_list = g_list_copy (sbz_data->embedded_profiles);
profile_list;
profile_list = g_list_next (profile_list))
{
SwatchBookerColorProfile *icc = profile_list->data;
if (! strcmp (sbz_data->color_space, icc->id))
{
space = gimp_color_profile_get_space (icc->profile,
GIMP_COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC,
NULL);
break;
}
}
}
for (i = 0; values[i]; i++)
true_values[i] = atof (values[i]);
/* No need for babl conversion for sRGB colors */
if (! strcmp (sbz_data->color_model, "srgb"))
{
gimp_rgb_set (&color, true_values[0], true_values[1],
true_values[2]);
load_pal = TRUE;
}
else if (! strcmp (sbz_data->color_model, "rgb"))
{
src_format = babl_format_with_space ("R'G'B' float", space);
}
else if (! strcmp (sbz_data->color_model, "gray"))
{
src_format = babl_format_with_space ("Y' float", space);
}
else if (! strcmp (sbz_data->color_model, "cmyk"))
{
src_format = babl_format_with_space ("CMYK float", space);
}
else if (! strcmp (sbz_data->color_model, "hsl"))
{
src_format = babl_format_with_space ("HSL float", space);
}
else if (! strcmp (sbz_data->color_model, "hsv"))
{
src_format = babl_format_with_space ("HSV float", space);
}
else if (! strcmp (sbz_data->color_model, "lab"))
{
src_format = babl_format_with_space ("CIE Lab float", space);
}
else if (! strcmp (sbz_data->color_model, "xyz"))
{
src_format = babl_format_with_space ("CIE XYZ float", space);
}
if (src_format != NULL)
{
gfloat rgb[3];
babl_process (babl_fish (src_format, dst_format),
true_values, rgb, 1);
gimp_rgb_set (&color, rgb[0], rgb[1], rgb[2]);
load_pal = TRUE;
}
if (load_pal)
{
gimp_palette_add_entry (sbz_data->palette, sbz_data->position,
NULL, &color);
if (sbz_data->palette_name)
gimp_palette_set_entry_name (sbz_data->palette,
sbz_data->position,
sbz_data->palette_name);
sbz_data->position++;
}
}
sbz_data->palette_name = NULL;
sbz_data->copy_values = FALSE;
if (sbz_data->color_model)
g_free (sbz_data->color_model);
}
}
GimpPaletteFileFormat
gimp_palette_load_detect_format (GFile *file,
GInputStream *input)
@@ -967,6 +1361,10 @@ gimp_palette_load_detect_format (GFile *file,
{
format = GIMP_PALETTE_FILE_FORMAT_CSS;
}
else if (g_str_has_suffix (lower, ".sbz"))
{
format = GIMP_PALETTE_FILE_FORMAT_SBZ;
}
g_free (lower);
}

View File

@@ -31,7 +31,8 @@ typedef enum
GIMP_PALETTE_FILE_FORMAT_PSP_PAL, /* JASC's Paint Shop Pro color palette */
GIMP_PALETTE_FILE_FORMAT_ACO, /* Photoshop ACO color file */
GIMP_PALETTE_FILE_FORMAT_ASE, /* Photoshop ASE color palette */
GIMP_PALETTE_FILE_FORMAT_CSS /* Cascaded Stylesheet file (CSS) */
GIMP_PALETTE_FILE_FORMAT_CSS, /* Cascaded Stylesheet file (CSS) */
GIMP_PALETTE_FILE_FORMAT_SBZ /* Swatchbooker SBZ file */
} GimpPaletteFileFormat;
@@ -63,6 +64,10 @@ GList * gimp_palette_load_css (GimpContext *context,
GFile *file,
GInputStream *input,
GError **error);
GList * gimp_palette_load_sbz (GimpContext *context,
GFile *file,
GInputStream *input,
GError **error);
GimpPaletteFileFormat gimp_palette_load_detect_format (GFile *file,
GInputStream *input);