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:
@@ -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,
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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);
|
||||
|
Reference in New Issue
Block a user