2006-12-10 05:33:38 +08:00
|
|
|
/* GIMP - The GNU Image Manipulation Program
|
2001-01-22 03:53:56 +08:00
|
|
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
|
|
|
*
|
2009-01-18 06:28:01 +08:00
|
|
|
* This program is free software: you can redistribute it and/or modify
|
2001-01-22 03:53:56 +08:00
|
|
|
* it under the terms of the GNU General Public License as published by
|
2009-01-18 06:28:01 +08:00
|
|
|
* the Free Software Foundation; either version 3 of the License, or
|
2001-01-22 03:53:56 +08:00
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program 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 General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
2018-07-12 05:27:07 +08:00
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
2001-01-22 03:53:56 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
2023-02-19 21:46:17 +08:00
|
|
|
#include <archive.h>
|
|
|
|
#include <archive_entry.h>
|
2011-04-28 21:50:39 +08:00
|
|
|
#include <cairo.h>
|
2012-05-03 09:36:22 +08:00
|
|
|
#include <gdk-pixbuf/gdk-pixbuf.h>
|
2023-02-19 21:46:17 +08:00
|
|
|
#include <gegl.h>
|
2006-10-03 22:31:31 +08:00
|
|
|
|
2003-10-16 20:24:58 +08:00
|
|
|
#include "libgimpbase/gimpbase.h"
|
2001-01-24 02:49:44 +08:00
|
|
|
#include "libgimpcolor/gimpcolor.h"
|
|
|
|
|
2001-05-10 06:34:59 +08:00
|
|
|
#include "core-types.h"
|
2001-01-22 03:53:56 +08:00
|
|
|
|
2023-02-19 21:46:17 +08:00
|
|
|
#include "config/gimpxmlparser.h"
|
|
|
|
|
Issue #1682 - Segfault when starting GIMP, due to empty data files
Use gimp_input_data_stream_read_line_always(), instead of
g_input_data_stream_read_line(), in a bunch of places that don't
expect EOF. If we don't do that, the code assumes the GError
parameter is set by the function and returns an error indication,
causing the caller to segfault when it tries to access
error->message. Instead, we now process an empty line when EOF is
reached, which is caught by the normal parsing logic.
Additionally:
- Use gimp_ascii_strto[id]() when loading gradients, generated
brushes, and palettes, to improve error checking for invalid
numeric input.
- Improve gradient-segment endpoint consistency check.
- Allow loading palette files with 0 colors. They can be created
during the session, so we might as well successfully load them.
2018-06-21 02:47:15 +08:00
|
|
|
#include "gimp-utils.h"
|
2001-01-22 03:53:56 +08:00
|
|
|
#include "gimppalette.h"
|
2006-10-03 21:22:12 +08:00
|
|
|
#include "gimppalette-load.h"
|
2001-05-10 06:34:59 +08:00
|
|
|
|
2003-03-26 00:38:19 +08:00
|
|
|
#include "gimp-intl.h"
|
2001-01-22 03:53:56 +08:00
|
|
|
|
2023-02-19 21:46:17 +08:00
|
|
|
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);
|
|
|
|
|
2023-09-12 18:59:26 +08:00
|
|
|
static gchar * gimp_palette_load_acb_string (GInputStream *input,
|
|
|
|
goffset file_size,
|
|
|
|
GError **error);
|
2023-08-28 00:51:02 +08:00
|
|
|
static gchar * gimp_palette_load_ase_block_name (GInputStream *input,
|
|
|
|
goffset file_size,
|
|
|
|
GError **error);
|
|
|
|
|
|
|
|
|
2013-09-15 14:46:28 +08:00
|
|
|
GList *
|
2014-07-04 09:31:03 +08:00
|
|
|
gimp_palette_load (GimpContext *context,
|
|
|
|
GFile *file,
|
|
|
|
GInputStream *input,
|
|
|
|
GError **error)
|
2001-01-22 03:53:56 +08:00
|
|
|
{
|
2014-07-03 21:49:58 +08:00
|
|
|
GimpPalette *palette = NULL;
|
|
|
|
GDataInputStream *data_input;
|
|
|
|
gchar *str;
|
|
|
|
gsize str_len;
|
2004-06-13 06:28:13 +08:00
|
|
|
gchar *tok;
|
|
|
|
gint linenum;
|
2001-01-22 03:53:56 +08:00
|
|
|
|
2014-07-01 20:25:37 +08:00
|
|
|
g_return_val_if_fail (G_IS_FILE (file), NULL);
|
2014-07-03 22:11:26 +08:00
|
|
|
g_return_val_if_fail (G_IS_INPUT_STREAM (input), NULL);
|
2002-12-02 21:39:09 +08:00
|
|
|
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
2001-01-22 03:53:56 +08:00
|
|
|
|
2014-07-03 22:11:26 +08:00
|
|
|
data_input = g_data_input_stream_new (input);
|
2014-07-03 21:49:58 +08:00
|
|
|
|
|
|
|
linenum = 1;
|
|
|
|
str_len = 1024;
|
Issue #1682 - Segfault when starting GIMP, due to empty data files
Use gimp_input_data_stream_read_line_always(), instead of
g_input_data_stream_read_line(), in a bunch of places that don't
expect EOF. If we don't do that, the code assumes the GError
parameter is set by the function and returns an error indication,
causing the caller to segfault when it tries to access
error->message. Instead, we now process an empty line when EOF is
reached, which is caught by the normal parsing logic.
Additionally:
- Use gimp_ascii_strto[id]() when loading gradients, generated
brushes, and palettes, to improve error checking for invalid
numeric input.
- Improve gradient-segment endpoint consistency check.
- Allow loading palette files with 0 colors. They can be created
during the session, so we might as well successfully load them.
2018-06-21 02:47:15 +08:00
|
|
|
str = gimp_data_input_stream_read_line_always (data_input, &str_len,
|
|
|
|
NULL, error);
|
2014-07-03 21:49:58 +08:00
|
|
|
if (! str)
|
|
|
|
goto failed;
|
2001-01-22 03:53:56 +08:00
|
|
|
|
2006-11-13 04:30:50 +08:00
|
|
|
if (! g_str_has_prefix (str, "GIMP Palette"))
|
2006-10-05 01:50:35 +08:00
|
|
|
{
|
2014-07-05 00:46:02 +08:00
|
|
|
g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
|
2014-07-03 21:49:58 +08:00
|
|
|
_("Missing magic header."));
|
|
|
|
g_free (str);
|
|
|
|
goto failed;
|
2001-01-22 03:53:56 +08:00
|
|
|
}
|
|
|
|
|
2014-07-21 03:40:57 +08:00
|
|
|
g_free (str);
|
|
|
|
|
2005-05-26 07:25:45 +08:00
|
|
|
palette = g_object_new (GIMP_TYPE_PALETTE,
|
|
|
|
"mime-type", "application/x-gimp-palette",
|
|
|
|
NULL);
|
2001-02-12 00:14:25 +08:00
|
|
|
|
2006-10-05 01:50:35 +08:00
|
|
|
linenum++;
|
2014-07-03 21:49:58 +08:00
|
|
|
str_len = 1024;
|
Issue #1682 - Segfault when starting GIMP, due to empty data files
Use gimp_input_data_stream_read_line_always(), instead of
g_input_data_stream_read_line(), in a bunch of places that don't
expect EOF. If we don't do that, the code assumes the GError
parameter is set by the function and returns an error indication,
causing the caller to segfault when it tries to access
error->message. Instead, we now process an empty line when EOF is
reached, which is caught by the normal parsing logic.
Additionally:
- Use gimp_ascii_strto[id]() when loading gradients, generated
brushes, and palettes, to improve error checking for invalid
numeric input.
- Improve gradient-segment endpoint consistency check.
- Allow loading palette files with 0 colors. They can be created
during the session, so we might as well successfully load them.
2018-06-21 02:47:15 +08:00
|
|
|
str = gimp_data_input_stream_read_line_always (data_input, &str_len,
|
|
|
|
NULL, error);
|
2014-07-03 21:49:58 +08:00
|
|
|
if (! str)
|
|
|
|
goto failed;
|
2001-02-12 00:14:25 +08:00
|
|
|
|
2006-11-13 04:30:50 +08:00
|
|
|
if (g_str_has_prefix (str, "Name: "))
|
2001-02-12 00:14:25 +08:00
|
|
|
{
|
2003-10-16 20:24:58 +08:00
|
|
|
gchar *utf8;
|
|
|
|
|
2006-10-05 01:50:35 +08:00
|
|
|
utf8 = gimp_any_to_utf8 (g_strstrip (str + strlen ("Name: ")), -1,
|
2003-10-16 20:24:58 +08:00
|
|
|
_("Invalid UTF-8 string in palette file '%s'"),
|
2014-07-01 20:25:37 +08:00
|
|
|
gimp_file_get_utf8_name (file));
|
2006-10-05 01:50:35 +08:00
|
|
|
gimp_object_take_name (GIMP_OBJECT (palette), utf8);
|
2014-07-03 21:49:58 +08:00
|
|
|
g_free (str);
|
2003-10-16 20:24:58 +08:00
|
|
|
|
2006-10-05 01:50:35 +08:00
|
|
|
linenum++;
|
2014-07-03 21:49:58 +08:00
|
|
|
str_len = 1024;
|
Issue #1682 - Segfault when starting GIMP, due to empty data files
Use gimp_input_data_stream_read_line_always(), instead of
g_input_data_stream_read_line(), in a bunch of places that don't
expect EOF. If we don't do that, the code assumes the GError
parameter is set by the function and returns an error indication,
causing the caller to segfault when it tries to access
error->message. Instead, we now process an empty line when EOF is
reached, which is caught by the normal parsing logic.
Additionally:
- Use gimp_ascii_strto[id]() when loading gradients, generated
brushes, and palettes, to improve error checking for invalid
numeric input.
- Improve gradient-segment endpoint consistency check.
- Allow loading palette files with 0 colors. They can be created
during the session, so we might as well successfully load them.
2018-06-21 02:47:15 +08:00
|
|
|
str = gimp_data_input_stream_read_line_always (data_input, &str_len,
|
|
|
|
NULL, error);
|
2014-07-03 21:49:58 +08:00
|
|
|
if (! str)
|
|
|
|
goto failed;
|
2001-01-22 03:53:56 +08:00
|
|
|
|
2006-11-13 04:30:50 +08:00
|
|
|
if (g_str_has_prefix (str, "Columns: "))
|
2004-06-30 19:09:44 +08:00
|
|
|
{
|
|
|
|
gint columns;
|
2001-02-13 02:05:12 +08:00
|
|
|
|
Issue #1682 - Segfault when starting GIMP, due to empty data files
Use gimp_input_data_stream_read_line_always(), instead of
g_input_data_stream_read_line(), in a bunch of places that don't
expect EOF. If we don't do that, the code assumes the GError
parameter is set by the function and returns an error indication,
causing the caller to segfault when it tries to access
error->message. Instead, we now process an empty line when EOF is
reached, which is caught by the normal parsing logic.
Additionally:
- Use gimp_ascii_strto[id]() when loading gradients, generated
brushes, and palettes, to improve error checking for invalid
numeric input.
- Improve gradient-segment endpoint consistency check.
- Allow loading palette files with 0 colors. They can be created
during the session, so we might as well successfully load them.
2018-06-21 02:47:15 +08:00
|
|
|
if (! gimp_ascii_strtoi (g_strstrip (str + strlen ("Columns: ")),
|
|
|
|
NULL, 10, &columns))
|
|
|
|
{
|
|
|
|
g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
|
|
|
|
_("Invalid column count."));
|
|
|
|
g_free (str);
|
|
|
|
goto failed;
|
|
|
|
}
|
2001-02-13 02:05:12 +08:00
|
|
|
|
2004-06-30 19:09:44 +08:00
|
|
|
if (columns < 0 || columns > 256)
|
|
|
|
{
|
|
|
|
g_message (_("Reading palette file '%s': "
|
|
|
|
"Invalid number of columns in line %d. "
|
2003-11-14 23:33:40 +08:00
|
|
|
"Using default value."),
|
2014-07-01 20:25:37 +08:00
|
|
|
gimp_file_get_utf8_name (file), linenum);
|
2004-06-30 19:09:44 +08:00
|
|
|
columns = 0;
|
|
|
|
}
|
2001-02-13 02:05:12 +08:00
|
|
|
|
2010-10-27 20:36:44 +08:00
|
|
|
gimp_palette_set_columns (palette, columns);
|
2014-07-03 21:49:58 +08:00
|
|
|
g_free (str);
|
2001-02-13 02:05:12 +08:00
|
|
|
|
2006-10-05 01:50:35 +08:00
|
|
|
linenum++;
|
2014-07-03 21:49:58 +08:00
|
|
|
str_len = 1024;
|
Issue #1682 - Segfault when starting GIMP, due to empty data files
Use gimp_input_data_stream_read_line_always(), instead of
g_input_data_stream_read_line(), in a bunch of places that don't
expect EOF. If we don't do that, the code assumes the GError
parameter is set by the function and returns an error indication,
causing the caller to segfault when it tries to access
error->message. Instead, we now process an empty line when EOF is
reached, which is caught by the normal parsing logic.
Additionally:
- Use gimp_ascii_strto[id]() when loading gradients, generated
brushes, and palettes, to improve error checking for invalid
numeric input.
- Improve gradient-segment endpoint consistency check.
- Allow loading palette files with 0 colors. They can be created
during the session, so we might as well successfully load them.
2018-06-21 02:47:15 +08:00
|
|
|
str = gimp_data_input_stream_read_line_always (data_input, &str_len,
|
|
|
|
NULL, error);
|
2014-07-03 21:49:58 +08:00
|
|
|
if (! str)
|
|
|
|
goto failed;
|
2004-06-30 19:09:44 +08:00
|
|
|
}
|
2001-02-12 00:14:25 +08:00
|
|
|
}
|
|
|
|
else /* old palette format */
|
|
|
|
{
|
2006-04-07 18:51:22 +08:00
|
|
|
gimp_object_take_name (GIMP_OBJECT (palette),
|
2014-07-01 20:25:37 +08:00
|
|
|
g_path_get_basename (gimp_file_get_utf8_name (file)));
|
2001-02-12 00:14:25 +08:00
|
|
|
}
|
|
|
|
|
2014-07-03 21:49:58 +08:00
|
|
|
while (str)
|
2001-02-12 00:14:25 +08:00
|
|
|
{
|
2014-07-05 00:46:02 +08:00
|
|
|
GError *my_error = NULL;
|
|
|
|
|
Issue #1682 - Segfault when starting GIMP, due to empty data files
Use gimp_input_data_stream_read_line_always(), instead of
g_input_data_stream_read_line(), in a bunch of places that don't
expect EOF. If we don't do that, the code assumes the GError
parameter is set by the function and returns an error indication,
causing the caller to segfault when it tries to access
error->message. Instead, we now process an empty line when EOF is
reached, which is caught by the normal parsing logic.
Additionally:
- Use gimp_ascii_strto[id]() when loading gradients, generated
brushes, and palettes, to improve error checking for invalid
numeric input.
- Improve gradient-segment endpoint consistency check.
- Allow loading palette files with 0 colors. They can be created
during the session, so we might as well successfully load them.
2018-06-21 02:47:15 +08:00
|
|
|
if (str[0] != '#' && str[0] != '\0')
|
2004-06-30 19:09:44 +08:00
|
|
|
{
|
2023-11-29 05:12:25 +08:00
|
|
|
GeglColor *color = gegl_color_new ("black");
|
|
|
|
guint8 rgb[3] = { 0 };
|
|
|
|
|
2004-06-30 19:09:44 +08:00
|
|
|
tok = strtok (str, " \t");
|
|
|
|
if (tok)
|
2023-11-29 05:12:25 +08:00
|
|
|
{
|
|
|
|
if (atoi (tok) < 0 || atoi (tok) > 255)
|
|
|
|
g_message (_("Reading palette file '%s': "
|
|
|
|
"red component out of range in line %d."),
|
|
|
|
gimp_file_get_utf8_name (file), linenum);
|
|
|
|
|
|
|
|
rgb[0] = CLAMP (atoi (tok), 0, 255);
|
|
|
|
}
|
2004-06-30 19:09:44 +08:00
|
|
|
else
|
2023-11-29 05:12:25 +08:00
|
|
|
{
|
|
|
|
g_message (_("Reading palette file '%s': "
|
|
|
|
"Missing RED component in line %d."),
|
|
|
|
gimp_file_get_utf8_name (file), linenum);
|
|
|
|
}
|
2001-01-22 03:53:56 +08:00
|
|
|
|
2004-06-30 19:09:44 +08:00
|
|
|
tok = strtok (NULL, " \t");
|
|
|
|
if (tok)
|
2023-11-29 05:12:25 +08:00
|
|
|
{
|
|
|
|
if (atoi (tok) < 0 || atoi (tok) > 255)
|
|
|
|
g_message (_("Reading palette file '%s': "
|
|
|
|
"green component out of range in line %d."),
|
|
|
|
gimp_file_get_utf8_name (file), linenum);
|
|
|
|
|
|
|
|
rgb[1] = CLAMP (atoi (tok), 0, 255);
|
|
|
|
}
|
2004-06-30 19:09:44 +08:00
|
|
|
else
|
2023-11-29 05:12:25 +08:00
|
|
|
{
|
|
|
|
g_message (_("Reading palette file '%s': "
|
|
|
|
"Missing GREEN component in line %d."),
|
|
|
|
gimp_file_get_utf8_name (file), linenum);
|
|
|
|
}
|
2001-01-22 03:53:56 +08:00
|
|
|
|
2004-06-30 19:09:44 +08:00
|
|
|
tok = strtok (NULL, " \t");
|
|
|
|
if (tok)
|
2023-11-29 05:12:25 +08:00
|
|
|
{
|
|
|
|
if (atoi (tok) < 0 || atoi (tok) > 255)
|
|
|
|
g_message (_("Reading palette file '%s': "
|
|
|
|
"blue component out of range in line %d."),
|
|
|
|
gimp_file_get_utf8_name (file), linenum);
|
|
|
|
|
|
|
|
rgb[2] = CLAMP (atoi (tok), 0, 255);
|
|
|
|
}
|
2004-06-30 19:09:44 +08:00
|
|
|
else
|
2023-11-29 05:12:25 +08:00
|
|
|
{
|
|
|
|
g_message (_("Reading palette file '%s': "
|
|
|
|
"Missing BLUE component in line %d."),
|
|
|
|
gimp_file_get_utf8_name (file), linenum);
|
|
|
|
}
|
2001-01-22 03:53:56 +08:00
|
|
|
|
2004-06-30 19:09:44 +08:00
|
|
|
/* optional name */
|
|
|
|
tok = strtok (NULL, "\n");
|
2001-01-22 03:53:56 +08:00
|
|
|
|
2023-11-29 05:12:25 +08:00
|
|
|
/* Historical .gpl format is sRGB. */
|
|
|
|
gegl_color_set_pixel (color, babl_format ("R'G'B' u8"), rgb);
|
|
|
|
gimp_palette_add_entry (palette, -1, tok, color);
|
|
|
|
g_object_unref (color);
|
2004-06-30 19:09:44 +08:00
|
|
|
}
|
2001-02-12 00:14:25 +08:00
|
|
|
|
2014-07-03 21:49:58 +08:00
|
|
|
g_free (str);
|
|
|
|
|
2006-10-05 01:50:35 +08:00
|
|
|
linenum++;
|
2014-07-03 21:49:58 +08:00
|
|
|
str_len = 1024;
|
|
|
|
str = g_data_input_stream_read_line (data_input, &str_len,
|
|
|
|
NULL, &my_error);
|
Issue #1682 - Segfault when starting GIMP, due to empty data files
Use gimp_input_data_stream_read_line_always(), instead of
g_input_data_stream_read_line(), in a bunch of places that don't
expect EOF. If we don't do that, the code assumes the GError
parameter is set by the function and returns an error indication,
causing the caller to segfault when it tries to access
error->message. Instead, we now process an empty line when EOF is
reached, which is caught by the normal parsing logic.
Additionally:
- Use gimp_ascii_strto[id]() when loading gradients, generated
brushes, and palettes, to improve error checking for invalid
numeric input.
- Improve gradient-segment endpoint consistency check.
- Allow loading palette files with 0 colors. They can be created
during the session, so we might as well successfully load them.
2018-06-21 02:47:15 +08:00
|
|
|
if (! str && my_error)
|
2004-06-30 19:09:44 +08:00
|
|
|
{
|
Issue #1682 - Segfault when starting GIMP, due to empty data files
Use gimp_input_data_stream_read_line_always(), instead of
g_input_data_stream_read_line(), in a bunch of places that don't
expect EOF. If we don't do that, the code assumes the GError
parameter is set by the function and returns an error indication,
causing the caller to segfault when it tries to access
error->message. Instead, we now process an empty line when EOF is
reached, which is caught by the normal parsing logic.
Additionally:
- Use gimp_ascii_strto[id]() when loading gradients, generated
brushes, and palettes, to improve error checking for invalid
numeric input.
- Improve gradient-segment endpoint consistency check.
- Allow loading palette files with 0 colors. They can be created
during the session, so we might as well successfully load them.
2018-06-21 02:47:15 +08:00
|
|
|
g_message (_("Reading palette file '%s': "
|
|
|
|
"Read %d colors from truncated file: %s"),
|
|
|
|
gimp_file_get_utf8_name (file),
|
|
|
|
g_list_length (palette->colors),
|
|
|
|
my_error->message);
|
|
|
|
g_clear_error (&my_error);
|
2004-06-30 19:09:44 +08:00
|
|
|
}
|
2001-01-22 03:53:56 +08:00
|
|
|
}
|
|
|
|
|
2014-07-03 21:49:58 +08:00
|
|
|
g_object_unref (data_input);
|
|
|
|
|
2004-07-27 03:00:22 +08:00
|
|
|
return g_list_prepend (NULL, palette);
|
2014-07-03 21:49:58 +08:00
|
|
|
|
|
|
|
failed:
|
|
|
|
|
|
|
|
g_object_unref (data_input);
|
|
|
|
|
|
|
|
if (palette)
|
|
|
|
g_object_unref (palette);
|
|
|
|
|
2014-07-05 00:46:02 +08:00
|
|
|
g_prefix_error (error, _("In line %d of palette file: "), linenum);
|
2014-07-03 21:49:58 +08:00
|
|
|
|
|
|
|
return NULL;
|
2001-01-22 03:53:56 +08:00
|
|
|
}
|
2006-10-03 22:31:31 +08:00
|
|
|
|
|
|
|
GList *
|
2014-07-03 22:42:37 +08:00
|
|
|
gimp_palette_load_act (GimpContext *context,
|
|
|
|
GFile *file,
|
|
|
|
GInputStream *input,
|
|
|
|
GError **error)
|
2006-10-03 22:31:31 +08:00
|
|
|
{
|
|
|
|
GimpPalette *palette;
|
|
|
|
gchar *palette_name;
|
2014-07-03 22:42:37 +08:00
|
|
|
guchar color_bytes[3];
|
|
|
|
gsize bytes_read;
|
2006-10-03 22:31:31 +08:00
|
|
|
|
2014-07-01 20:25:37 +08:00
|
|
|
g_return_val_if_fail (G_IS_FILE (file), NULL);
|
2018-06-10 13:43:57 +08:00
|
|
|
g_return_val_if_fail (G_IS_INPUT_STREAM (input), NULL);
|
2006-10-03 22:31:31 +08:00
|
|
|
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
|
|
|
|
2014-07-01 20:25:37 +08:00
|
|
|
palette_name = g_path_get_basename (gimp_file_get_utf8_name (file));
|
2010-04-11 01:55:42 +08:00
|
|
|
palette = GIMP_PALETTE (gimp_palette_new (context, palette_name));
|
2006-10-03 22:31:31 +08:00
|
|
|
g_free (palette_name);
|
|
|
|
|
2014-07-03 22:42:37 +08:00
|
|
|
while (g_input_stream_read_all (input, color_bytes, sizeof (color_bytes),
|
|
|
|
&bytes_read, NULL, NULL) &&
|
|
|
|
bytes_read == sizeof (color_bytes))
|
2006-10-03 22:31:31 +08:00
|
|
|
{
|
2023-11-29 05:12:25 +08:00
|
|
|
/* The spec is absolutely unclear and just says:
|
|
|
|
* > If loaded into the Colors palette, the colors will be installed in the color swatch list as RGB colors.
|
|
|
|
* So should these be sRGB colors? Anyway since palettes are not attached
|
|
|
|
* to images (except in specific case of indexed images), we can't use a
|
|
|
|
* specific image's color space and the format simply has no color space
|
|
|
|
* information.
|
|
|
|
* So we just assume these colors are sRGB.
|
|
|
|
*/
|
|
|
|
GeglColor *color = gegl_color_new (NULL);
|
|
|
|
|
|
|
|
gegl_color_set_pixel (color, babl_format ("R'G'B' u8"), color_bytes);
|
|
|
|
gimp_palette_add_entry (palette, -1, NULL, color);
|
|
|
|
|
|
|
|
g_object_unref (color);
|
2006-10-03 22:31:31 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return g_list_prepend (NULL, palette);
|
|
|
|
}
|
|
|
|
|
|
|
|
GList *
|
2014-07-03 22:42:37 +08:00
|
|
|
gimp_palette_load_riff (GimpContext *context,
|
|
|
|
GFile *file,
|
|
|
|
GInputStream *input,
|
|
|
|
GError **error)
|
2006-10-03 22:31:31 +08:00
|
|
|
{
|
|
|
|
GimpPalette *palette;
|
|
|
|
gchar *palette_name;
|
|
|
|
guchar color_bytes[4];
|
2014-07-03 22:42:37 +08:00
|
|
|
gsize bytes_read;
|
2006-10-03 22:31:31 +08:00
|
|
|
|
2014-07-01 20:25:37 +08:00
|
|
|
g_return_val_if_fail (G_IS_FILE (file), NULL);
|
2018-06-10 13:43:57 +08:00
|
|
|
g_return_val_if_fail (G_IS_INPUT_STREAM (input), NULL);
|
2006-10-03 22:31:31 +08:00
|
|
|
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
|
|
|
|
2014-07-01 20:25:37 +08:00
|
|
|
palette_name = g_path_get_basename (gimp_file_get_utf8_name (file));
|
2010-04-11 01:55:42 +08:00
|
|
|
palette = GIMP_PALETTE (gimp_palette_new (context, palette_name));
|
2006-10-03 22:31:31 +08:00
|
|
|
g_free (palette_name);
|
|
|
|
|
2014-07-03 22:42:37 +08:00
|
|
|
if (! g_seekable_seek (G_SEEKABLE (input), 28, G_SEEK_SET, NULL, error))
|
2014-07-03 22:59:04 +08:00
|
|
|
{
|
|
|
|
g_object_unref (palette);
|
|
|
|
return NULL;
|
|
|
|
}
|
2008-11-07 17:32:23 +08:00
|
|
|
|
2014-07-03 22:42:37 +08:00
|
|
|
while (g_input_stream_read_all (input, color_bytes, sizeof (color_bytes),
|
|
|
|
&bytes_read, NULL, NULL) &&
|
|
|
|
bytes_read == sizeof (color_bytes))
|
2006-10-03 22:31:31 +08:00
|
|
|
{
|
2023-11-29 05:12:25 +08:00
|
|
|
GeglColor *color = gegl_color_new (NULL);
|
|
|
|
|
|
|
|
/* The format does not include color space information. The fourth byte is
|
|
|
|
* called peFlags but possible values in Microsoft documentation does not
|
|
|
|
* list space-related flags.
|
|
|
|
* So as often with such historical formats, we assume that by "RGB" they
|
|
|
|
* meant "sRGB".
|
|
|
|
*/
|
|
|
|
gegl_color_set_pixel (color, babl_format ("R'G'B' u8"), color_bytes);
|
|
|
|
gimp_palette_add_entry (palette, -1, NULL, color);
|
|
|
|
|
|
|
|
g_object_unref (color);
|
2006-10-03 22:31:31 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return g_list_prepend (NULL, palette);
|
|
|
|
}
|
|
|
|
|
|
|
|
GList *
|
2014-07-03 22:59:04 +08:00
|
|
|
gimp_palette_load_psp (GimpContext *context,
|
|
|
|
GFile *file,
|
|
|
|
GInputStream *input,
|
|
|
|
GError **error)
|
2006-10-03 22:31:31 +08:00
|
|
|
{
|
|
|
|
GimpPalette *palette;
|
|
|
|
gchar *palette_name;
|
|
|
|
guchar color_bytes[4];
|
|
|
|
gint number_of_colors;
|
2014-07-03 22:59:04 +08:00
|
|
|
gsize bytes_read;
|
2006-10-03 22:31:31 +08:00
|
|
|
gint i, j;
|
|
|
|
gboolean color_ok;
|
|
|
|
gchar buffer[4096];
|
|
|
|
/*Maximum valid file size: 256 * 4 * 3 + 256 * 2 ~= 3650 bytes */
|
|
|
|
gchar **lines;
|
|
|
|
gchar **ascii_colors;
|
|
|
|
|
2014-07-01 20:25:37 +08:00
|
|
|
g_return_val_if_fail (G_IS_FILE (file), NULL);
|
2018-06-10 13:43:57 +08:00
|
|
|
g_return_val_if_fail (G_IS_INPUT_STREAM (input), NULL);
|
2006-10-03 22:31:31 +08:00
|
|
|
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
|
|
|
|
2014-07-01 20:25:37 +08:00
|
|
|
palette_name = g_path_get_basename (gimp_file_get_utf8_name (file));
|
2010-04-11 01:55:42 +08:00
|
|
|
palette = GIMP_PALETTE (gimp_palette_new (context, palette_name));
|
2006-10-03 22:31:31 +08:00
|
|
|
g_free (palette_name);
|
|
|
|
|
2014-07-03 22:59:04 +08:00
|
|
|
if (! g_seekable_seek (G_SEEKABLE (input), 16, G_SEEK_SET, NULL, error))
|
|
|
|
{
|
|
|
|
g_object_unref (palette);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (! g_input_stream_read_all (input, buffer, sizeof (buffer) - 1,
|
|
|
|
&bytes_read, NULL, error))
|
|
|
|
{
|
|
|
|
g_object_unref (palette);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
buffer[bytes_read] = '\0';
|
2006-10-03 22:31:31 +08:00
|
|
|
|
|
|
|
lines = g_strsplit (buffer, "\x0d\x0a", -1);
|
|
|
|
|
|
|
|
number_of_colors = atoi (lines[0]);
|
|
|
|
|
|
|
|
for (i = 0; i < number_of_colors; i++)
|
|
|
|
{
|
|
|
|
if (lines[i + 1] == NULL)
|
|
|
|
{
|
|
|
|
g_printerr ("Premature end of file reading %s.",
|
2014-07-01 20:25:37 +08:00
|
|
|
gimp_file_get_utf8_name (file));
|
2006-10-03 22:31:31 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
ascii_colors = g_strsplit (lines[i + 1], " ", 3);
|
|
|
|
color_ok = TRUE;
|
|
|
|
|
|
|
|
for (j = 0 ; j < 3; j++)
|
|
|
|
{
|
|
|
|
if (ascii_colors[j] == NULL)
|
|
|
|
{
|
|
|
|
g_printerr ("Corrupted palette file %s.",
|
2014-07-01 20:25:37 +08:00
|
|
|
gimp_file_get_utf8_name (file));
|
2006-10-03 22:31:31 +08:00
|
|
|
color_ok = FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
color_bytes[j] = atoi (ascii_colors[j]);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (color_ok)
|
|
|
|
{
|
2023-11-29 05:12:25 +08:00
|
|
|
GeglColor *color = gegl_color_new (NULL);
|
|
|
|
|
|
|
|
/* The format does not include color space information. Assuming sRGB
|
|
|
|
* like for all such historical formats.
|
|
|
|
*/
|
|
|
|
gegl_color_set_pixel (color, babl_format ("R'G'B' u8"), color_bytes);
|
|
|
|
gimp_palette_add_entry (palette, -1, NULL, color);
|
|
|
|
|
|
|
|
g_object_unref (color);
|
2006-10-03 22:31:31 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
g_strfreev (ascii_colors);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_strfreev (lines);
|
|
|
|
|
|
|
|
return g_list_prepend (NULL, palette);
|
|
|
|
}
|
2006-10-03 22:54:07 +08:00
|
|
|
|
2007-08-07 21:42:55 +08:00
|
|
|
GList *
|
2014-07-03 23:23:11 +08:00
|
|
|
gimp_palette_load_aco (GimpContext *context,
|
|
|
|
GFile *file,
|
|
|
|
GInputStream *input,
|
|
|
|
GError **error)
|
2007-08-07 21:42:55 +08:00
|
|
|
{
|
|
|
|
GimpPalette *palette;
|
|
|
|
gchar *palette_name;
|
|
|
|
gint format_version;
|
|
|
|
gint number_of_colors;
|
|
|
|
gint i;
|
|
|
|
gchar header[4];
|
2014-07-03 23:23:11 +08:00
|
|
|
gsize bytes_read;
|
2007-08-07 21:42:55 +08:00
|
|
|
|
2014-07-01 20:25:37 +08:00
|
|
|
g_return_val_if_fail (G_IS_FILE (file), NULL);
|
2018-06-10 13:43:57 +08:00
|
|
|
g_return_val_if_fail (G_IS_INPUT_STREAM (input), NULL);
|
2007-08-07 21:42:55 +08:00
|
|
|
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
|
|
|
|
2014-07-03 23:23:11 +08:00
|
|
|
if (! g_input_stream_read_all (input, header, sizeof (header),
|
|
|
|
&bytes_read, NULL, error) ||
|
|
|
|
bytes_read != sizeof (header))
|
2007-08-07 21:42:55 +08:00
|
|
|
{
|
2024-06-11 20:43:39 +08:00
|
|
|
g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
|
|
|
|
_("Could not read header from palette file '%s': "),
|
|
|
|
gimp_file_get_utf8_name (file));
|
2008-11-07 17:32:23 +08:00
|
|
|
return NULL;
|
2007-08-07 21:42:55 +08:00
|
|
|
}
|
|
|
|
|
2014-07-01 20:25:37 +08:00
|
|
|
palette_name = g_path_get_basename (gimp_file_get_utf8_name (file));
|
2010-04-11 01:55:42 +08:00
|
|
|
palette = GIMP_PALETTE (gimp_palette_new (context, palette_name));
|
2008-11-07 17:32:23 +08:00
|
|
|
g_free (palette_name);
|
|
|
|
|
2014-07-03 23:23:11 +08:00
|
|
|
format_version = header[1] + (header[0] << 8);
|
2007-08-07 21:42:55 +08:00
|
|
|
number_of_colors = header[3] + (header[2] << 8);
|
|
|
|
|
|
|
|
for (i = 0; i < number_of_colors; i++)
|
2008-11-07 17:32:23 +08:00
|
|
|
{
|
2023-11-29 05:12:25 +08:00
|
|
|
GeglColor *color;
|
2023-02-25 12:49:23 +08:00
|
|
|
gchar color_info[10];
|
|
|
|
gint color_space;
|
|
|
|
gint w, x, y, z;
|
|
|
|
gint xLab;
|
|
|
|
gint yLab;
|
|
|
|
gboolean color_ok = FALSE;
|
|
|
|
GError *my_error = NULL;
|
2014-07-03 23:23:11 +08:00
|
|
|
|
|
|
|
if (! g_input_stream_read_all (input, color_info, sizeof (color_info),
|
|
|
|
&bytes_read, NULL, &my_error) ||
|
|
|
|
bytes_read != sizeof (color_info))
|
2016-11-25 12:51:03 +08:00
|
|
|
{
|
2014-07-03 23:23:11 +08:00
|
|
|
if (palette->colors)
|
|
|
|
{
|
|
|
|
g_message (_("Reading palette file '%s': "
|
|
|
|
"Read %d colors from truncated file: %s"),
|
|
|
|
gimp_file_get_utf8_name (file),
|
|
|
|
g_list_length (palette->colors),
|
|
|
|
my_error ?
|
|
|
|
my_error->message : _("Premature end of file."));
|
|
|
|
g_clear_error (&my_error);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2014-07-05 00:46:02 +08:00
|
|
|
g_propagate_error (error, my_error);
|
2008-11-07 17:32:23 +08:00
|
|
|
g_object_unref (palette);
|
2014-07-03 23:23:11 +08:00
|
|
|
|
2008-11-07 17:32:23 +08:00
|
|
|
return NULL;
|
2016-11-25 12:51:03 +08:00
|
|
|
}
|
2007-08-07 21:42:55 +08:00
|
|
|
|
|
|
|
color_space = color_info[1] + (color_info[0] << 8);
|
|
|
|
|
|
|
|
w = (guchar) color_info[3] + ((guchar) color_info[2] << 8);
|
|
|
|
x = (guchar) color_info[5] + ((guchar) color_info[4] << 8);
|
|
|
|
y = (guchar) color_info[7] + ((guchar) color_info[6] << 8);
|
|
|
|
z = (guchar) color_info[9] + ((guchar) color_info[8] << 8);
|
2023-02-25 12:49:23 +08:00
|
|
|
/* Lab-specific values */
|
|
|
|
xLab = (gint) color_info[5] | ((gint) color_info[4] << 8);
|
|
|
|
yLab = (gint) color_info[7] | ((gint) color_info[6] << 8);
|
|
|
|
if (xLab >= 32768)
|
|
|
|
xLab -= 65536;
|
|
|
|
if (yLab >= 32768)
|
|
|
|
yLab -= 65536;
|
2007-08-07 21:42:55 +08:00
|
|
|
|
2023-11-29 05:12:25 +08:00
|
|
|
color = gegl_color_new (NULL);
|
2007-08-07 21:42:55 +08:00
|
|
|
if (color_space == 0) /* RGB */
|
2008-11-07 17:32:23 +08:00
|
|
|
{
|
2023-02-25 12:49:23 +08:00
|
|
|
gdouble rgb[3] = { ((gdouble) w) / 65536.0,
|
|
|
|
((gdouble) x) / 65536.0,
|
|
|
|
((gdouble) y) / 65536.0 };
|
2007-08-07 21:42:55 +08:00
|
|
|
|
2023-11-29 05:12:25 +08:00
|
|
|
/* No color space information in the format. */
|
|
|
|
gegl_color_set_pixel (color, babl_format ("R'G'B' double"), rgb);
|
2008-11-07 17:32:23 +08:00
|
|
|
color_ok = TRUE;
|
|
|
|
}
|
2007-08-07 21:42:55 +08:00
|
|
|
else if (color_space == 1) /* HSV */
|
2008-11-07 17:32:23 +08:00
|
|
|
{
|
2024-04-21 11:42:27 +08:00
|
|
|
gfloat hsv[3] = { ((gfloat) w) / 65536.0f,
|
|
|
|
((gfloat) x) / 65536.0f,
|
|
|
|
((gfloat) y) / 65536.0f};
|
2007-08-07 21:42:55 +08:00
|
|
|
|
2024-04-21 11:42:27 +08:00
|
|
|
gegl_color_set_pixel (color, babl_format ("HSV float"), hsv);
|
2008-11-07 17:32:23 +08:00
|
|
|
color_ok = TRUE;
|
|
|
|
}
|
2007-08-07 21:42:55 +08:00
|
|
|
else if (color_space == 2) /* CMYK */
|
2008-11-07 17:32:23 +08:00
|
|
|
{
|
2024-04-23 21:38:59 +08:00
|
|
|
float cmyk[4] = { 1.0f - ((gfloat) w) / 65536.0f,
|
|
|
|
1.0f - ((gfloat) x) / 65536.0f,
|
|
|
|
1.0f - ((gfloat) y) / 65536.0f,
|
|
|
|
1.0f - ((gfloat) z) / 65536.0f };
|
2023-02-25 12:49:23 +08:00
|
|
|
|
2023-11-29 05:12:25 +08:00
|
|
|
/* No color space information in the format. */
|
2024-04-23 21:38:59 +08:00
|
|
|
gegl_color_set_pixel (color, babl_format ("CMYK float"), cmyk);
|
2023-02-25 12:49:23 +08:00
|
|
|
color_ok = TRUE;
|
|
|
|
}
|
|
|
|
else if (color_space == 7) /* CIE Lab */
|
|
|
|
{
|
|
|
|
gdouble lab[3] = { ((gdouble) w) / 10000.0,
|
|
|
|
((gdouble) xLab) / 25500.0,
|
|
|
|
((gdouble) yLab) / 25500.0 };
|
2007-08-07 21:42:55 +08:00
|
|
|
|
2023-11-29 05:12:25 +08:00
|
|
|
gegl_color_set_pixel (color, babl_format ("CIE Lab double"), lab);
|
2008-11-07 17:32:23 +08:00
|
|
|
color_ok = TRUE;
|
|
|
|
}
|
2007-08-07 21:42:55 +08:00
|
|
|
else if (color_space == 8) /* Grayscale */
|
2008-11-07 17:32:23 +08:00
|
|
|
{
|
2023-02-25 12:49:23 +08:00
|
|
|
gdouble k[1] = { 1.0 - (((gdouble) w) / 10000.0) };
|
2007-08-07 21:42:55 +08:00
|
|
|
|
2023-11-29 05:12:25 +08:00
|
|
|
/* No color space information in the format. */
|
|
|
|
gegl_color_set_pixel (color, babl_format ("Y' double"), k);
|
2008-11-07 17:32:23 +08:00
|
|
|
color_ok = TRUE;
|
|
|
|
}
|
2007-08-07 21:42:55 +08:00
|
|
|
else if (color_space == 9) /* Wide? CMYK */
|
2008-11-07 17:32:23 +08:00
|
|
|
{
|
2023-11-29 05:12:25 +08:00
|
|
|
/* XXX: this "Color Space ID" 8 does not exist in Adobe specification.
|
|
|
|
* Apparently this case was present ever since the first
|
|
|
|
* implementation in GIMP so it's hard to know the origin behind it.
|
|
|
|
* Where does it come from?
|
|
|
|
*/
|
2024-04-23 21:38:59 +08:00
|
|
|
gfloat cmyk[4] = { 1.0f - ((gfloat) w) / 10000.0,
|
|
|
|
1.0f - ((gfloat) x) / 10000.0,
|
|
|
|
1.0f - ((gfloat) y) / 10000.0,
|
|
|
|
1.0f - ((gfloat) z) / 10000.0 };
|
2007-08-07 21:42:55 +08:00
|
|
|
|
2024-04-23 21:38:59 +08:00
|
|
|
gegl_color_set_pixel (color, babl_format ("CMYK float"), cmyk);
|
2008-11-07 17:32:23 +08:00
|
|
|
color_ok = TRUE;
|
|
|
|
}
|
2007-08-07 21:42:55 +08:00
|
|
|
else
|
2008-11-07 17:32:23 +08:00
|
|
|
{
|
|
|
|
g_printerr ("Unsupported color space (%d) in ACO file %s\n",
|
2014-07-01 20:25:37 +08:00
|
|
|
color_space, gimp_file_get_utf8_name (file));
|
2008-11-07 17:32:23 +08:00
|
|
|
}
|
2007-08-07 21:42:55 +08:00
|
|
|
|
|
|
|
if (format_version == 2)
|
2008-11-07 17:32:23 +08:00
|
|
|
{
|
2014-07-03 23:23:11 +08:00
|
|
|
gchar format2_preamble[4];
|
|
|
|
gint number_of_chars;
|
|
|
|
|
|
|
|
if (! g_input_stream_read_all (input,
|
|
|
|
format2_preamble,
|
|
|
|
sizeof (format2_preamble),
|
2014-07-05 00:46:02 +08:00
|
|
|
&bytes_read, NULL, error) ||
|
2014-07-03 23:23:11 +08:00
|
|
|
bytes_read != sizeof (format2_preamble))
|
2016-11-25 12:51:03 +08:00
|
|
|
{
|
|
|
|
g_object_unref (palette);
|
2023-11-29 05:12:25 +08:00
|
|
|
g_object_unref (color);
|
2016-11-25 12:51:03 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
2008-11-07 17:32:23 +08:00
|
|
|
|
|
|
|
number_of_chars = format2_preamble[3] + (format2_preamble[2] << 8);
|
2014-07-03 23:23:11 +08:00
|
|
|
|
2023-11-29 05:12:25 +08:00
|
|
|
/* TODO: color name should be used (by converting from UTF-16 to
|
|
|
|
* UTF-8), not ignored. Also according to spec, there should be 2
|
|
|
|
* additional NUL bytes at the end, which are not (I think) counted in
|
|
|
|
* number_of_chars). Therefore this code may be wrong and missing 2
|
|
|
|
* bytes.
|
|
|
|
*/
|
2014-07-03 23:23:11 +08:00
|
|
|
if (! g_seekable_seek (G_SEEKABLE (input), number_of_chars * 2,
|
|
|
|
G_SEEK_SET, NULL, error))
|
|
|
|
{
|
|
|
|
g_object_unref (palette);
|
2023-11-29 05:12:25 +08:00
|
|
|
g_object_unref (color);
|
2014-07-03 23:23:11 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
2008-11-07 17:32:23 +08:00
|
|
|
}
|
2007-08-07 21:42:55 +08:00
|
|
|
|
|
|
|
if (color_ok)
|
2023-11-29 05:12:25 +08:00
|
|
|
gimp_palette_add_entry (palette, -1, NULL, color);
|
|
|
|
|
|
|
|
g_object_unref (color);
|
2008-11-07 17:32:23 +08:00
|
|
|
}
|
2007-08-07 21:42:55 +08:00
|
|
|
|
|
|
|
return g_list_prepend (NULL, palette);
|
|
|
|
}
|
|
|
|
|
2023-09-12 18:59:26 +08:00
|
|
|
GList *
|
|
|
|
gimp_palette_load_acb (GimpContext *context,
|
|
|
|
GFile *file,
|
|
|
|
GInputStream *input,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
GimpPalette *palette;
|
|
|
|
gchar header[4];
|
|
|
|
gshort version;
|
|
|
|
gchar **palette_strings;
|
|
|
|
gchar *palette_name;
|
|
|
|
gchar **palette_prefix;
|
|
|
|
gchar **palette_suffix;
|
|
|
|
gchar *description;
|
|
|
|
gushort number_of_colors;
|
|
|
|
gushort page;
|
|
|
|
gushort color_space;
|
|
|
|
gint i;
|
|
|
|
goffset file_size;
|
|
|
|
gsize bytes_read;
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
/* Get file size */
|
|
|
|
g_seekable_seek (G_SEEKABLE (input), 0, G_SEEK_END, NULL, error);
|
|
|
|
file_size = g_seekable_tell (G_SEEKABLE (input));
|
|
|
|
g_seekable_seek (G_SEEKABLE (input), 0, G_SEEK_SET, NULL, error);
|
|
|
|
|
|
|
|
if (! g_input_stream_read_all (input, header, sizeof (header),
|
|
|
|
&bytes_read, NULL, error) ||
|
|
|
|
bytes_read != sizeof (header))
|
|
|
|
{
|
2024-06-11 20:43:39 +08:00
|
|
|
g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
|
|
|
|
_("Could not read header from palette file '%s': "),
|
|
|
|
gimp_file_get_utf8_name (file));
|
2023-09-12 18:59:26 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Version and ID */
|
|
|
|
if (! g_input_stream_read_all (input, &version, sizeof (version),
|
|
|
|
&bytes_read, NULL, error))
|
|
|
|
{
|
2024-06-11 20:43:39 +08:00
|
|
|
g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
|
|
|
|
_("Invalid ACB palette version."));
|
2023-09-12 18:59:26 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
version = GUINT16_FROM_BE (version);
|
|
|
|
if (version != 1)
|
|
|
|
{
|
2024-06-11 20:43:39 +08:00
|
|
|
g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
|
|
|
|
_("GIMP only supports version 1 ACB palettes"));
|
2023-09-12 18:59:26 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (! g_input_stream_read_all (input, &version, sizeof (version),
|
|
|
|
&bytes_read, NULL, error))
|
|
|
|
{
|
2024-06-11 20:43:39 +08:00
|
|
|
g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
|
|
|
|
_("Invalid ACB palette identifier."));
|
2023-09-12 18:59:26 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Color Book name and palette prefix/suffix */
|
|
|
|
palette_name = gimp_palette_load_acb_string (input, file_size, error);
|
|
|
|
if (palette_name)
|
|
|
|
palette_strings = g_strsplit (palette_name, "=", -1);
|
|
|
|
if (! palette_name || g_strv_length (palette_strings) != 2)
|
|
|
|
{
|
|
|
|
if (palette_name)
|
|
|
|
{
|
|
|
|
g_strfreev (palette_strings);
|
|
|
|
g_free (palette_name);
|
|
|
|
}
|
2024-06-11 20:43:39 +08:00
|
|
|
g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
|
|
|
|
_("Invalid ACB palette name."));
|
2023-09-12 18:59:26 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
palette = GIMP_PALETTE (gimp_palette_new (context, palette_strings[1]));
|
|
|
|
|
|
|
|
g_strfreev (palette_strings);
|
|
|
|
g_free (palette_name);
|
|
|
|
|
|
|
|
palette_name = gimp_palette_load_acb_string (input, file_size, error);
|
|
|
|
if (palette_name)
|
|
|
|
palette_prefix = g_strsplit (palette_name, "=", -1);
|
|
|
|
if (! palette_name || g_strv_length (palette_prefix) != 2)
|
|
|
|
{
|
|
|
|
if (palette_name)
|
|
|
|
{
|
|
|
|
g_strfreev (palette_prefix);
|
|
|
|
g_free (palette_name);
|
|
|
|
}
|
2024-06-11 20:43:39 +08:00
|
|
|
g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
|
|
|
|
_("Invalid ACB palette name."));
|
2023-09-12 18:59:26 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
g_free (palette_name);
|
|
|
|
|
|
|
|
palette_name = gimp_palette_load_acb_string (input, file_size, error);
|
|
|
|
if (palette_name)
|
|
|
|
palette_suffix = g_strsplit (palette_name, "=", -1);
|
|
|
|
if (! palette_name || g_strv_length (palette_suffix) != 2)
|
|
|
|
{
|
|
|
|
if (palette_name)
|
|
|
|
{
|
|
|
|
g_strfreev (palette_suffix);
|
|
|
|
g_free (palette_name);
|
|
|
|
}
|
2024-06-11 20:43:39 +08:00
|
|
|
g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
|
|
|
|
_("Invalid ACB palette suffix."));
|
2023-09-12 18:59:26 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
g_free (palette_name);
|
|
|
|
|
|
|
|
/* Description (currently unused) */
|
|
|
|
description = gimp_palette_load_acb_string (input, file_size,
|
|
|
|
error);
|
|
|
|
g_free (description);
|
|
|
|
|
|
|
|
/* Number of colors */
|
|
|
|
if (! g_input_stream_read_all (input, &number_of_colors,
|
|
|
|
sizeof (number_of_colors), &bytes_read, NULL,
|
|
|
|
error))
|
|
|
|
{
|
|
|
|
g_strfreev (palette_prefix);
|
|
|
|
g_strfreev (palette_suffix);
|
|
|
|
|
2024-06-11 20:43:39 +08:00
|
|
|
g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
|
|
|
|
_("Invalid number of colors in palette."));
|
2023-09-12 18:59:26 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
number_of_colors = GUINT16_FROM_BE (number_of_colors);
|
|
|
|
if (number_of_colors <= 1)
|
|
|
|
{
|
2024-06-11 20:43:39 +08:00
|
|
|
g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
|
|
|
|
_("Invalid number of colors: %s."),
|
|
|
|
gimp_file_get_utf8_name (file));
|
2023-09-12 18:59:26 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Page information (currently unused) */
|
|
|
|
if (! g_input_stream_read_all (input, &page, sizeof (page),
|
|
|
|
&bytes_read, NULL, error))
|
|
|
|
{
|
|
|
|
g_strfreev (palette_prefix);
|
|
|
|
g_strfreev (palette_suffix);
|
|
|
|
|
2024-06-11 20:43:39 +08:00
|
|
|
g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
|
|
|
|
_("Invalid ACB palette page info."));
|
2023-09-12 18:59:26 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (! g_input_stream_read_all (input, &page, sizeof (page),
|
|
|
|
&bytes_read, NULL, error))
|
|
|
|
{
|
|
|
|
g_strfreev (palette_prefix);
|
|
|
|
g_strfreev (palette_suffix);
|
|
|
|
|
2024-06-11 20:43:39 +08:00
|
|
|
g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
|
|
|
|
_("Invalid ACB palette page info."));
|
2023-09-12 18:59:26 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Color Model */
|
|
|
|
if (! g_input_stream_read_all (input, &color_space, sizeof (color_space),
|
|
|
|
&bytes_read, NULL, error))
|
|
|
|
{
|
|
|
|
g_strfreev (palette_prefix);
|
|
|
|
g_strfreev (palette_suffix);
|
|
|
|
|
2024-06-11 20:43:39 +08:00
|
|
|
g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
|
|
|
|
_("Invalid ACB palette color space."));
|
2023-09-12 18:59:26 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
color_space = GUINT16_FROM_BE (color_space);
|
|
|
|
|
2023-11-29 05:12:25 +08:00
|
|
|
if (color_space != 0 &&
|
|
|
|
color_space != 2 &&
|
|
|
|
color_space != 7)
|
2023-09-12 18:59:26 +08:00
|
|
|
{
|
|
|
|
g_strfreev (palette_prefix);
|
|
|
|
g_strfreev (palette_suffix);
|
|
|
|
|
2024-06-11 20:43:39 +08:00
|
|
|
g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
|
|
|
|
_("Invalid ACB palette color space."));
|
2023-09-12 18:59:26 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Color records */
|
|
|
|
for (i = 0; i < number_of_colors; i++)
|
|
|
|
{
|
2023-11-29 05:12:25 +08:00
|
|
|
GeglColor *color = gegl_color_new (NULL);
|
|
|
|
gchar color_code[6];
|
|
|
|
gchar *palette_entry = NULL;
|
|
|
|
gchar *full_palette_name = NULL;
|
|
|
|
gboolean color_ok = FALSE;
|
2023-09-12 18:59:26 +08:00
|
|
|
|
|
|
|
palette_entry = gimp_palette_load_acb_string (input, file_size,
|
|
|
|
error);
|
|
|
|
|
|
|
|
if (palette_entry)
|
|
|
|
full_palette_name = g_strdup_printf ("%s%s %s", palette_prefix[1],
|
|
|
|
palette_entry, palette_suffix[1]);
|
|
|
|
|
|
|
|
/* Color Code (not used) */
|
|
|
|
if (! g_input_stream_read_all (input, color_code, sizeof (color_code),
|
|
|
|
&bytes_read, NULL, error))
|
|
|
|
{
|
|
|
|
g_free (palette_entry);
|
|
|
|
g_free (full_palette_name);
|
2023-11-29 05:12:25 +08:00
|
|
|
g_object_unref (color);
|
2023-09-12 18:59:26 +08:00
|
|
|
|
|
|
|
g_printerr ("Invalid ACB palette color code");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (color_space == 0)
|
|
|
|
{
|
|
|
|
gchar rgb[3];
|
|
|
|
|
|
|
|
if (! g_input_stream_read_all (input, rgb, sizeof (rgb),
|
|
|
|
&bytes_read, NULL, error))
|
|
|
|
{
|
|
|
|
g_free (palette_entry);
|
|
|
|
g_free (full_palette_name);
|
2023-11-29 05:12:25 +08:00
|
|
|
g_object_unref (color);
|
2023-09-12 18:59:26 +08:00
|
|
|
|
|
|
|
g_printerr ("Invalid ACB palette colors");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2023-11-29 05:12:25 +08:00
|
|
|
gegl_color_set_pixel (color, babl_format ("R'G'B u8"), rgb);
|
2023-09-12 18:59:26 +08:00
|
|
|
color_ok = TRUE;
|
|
|
|
}
|
|
|
|
else if (color_space == 2)
|
|
|
|
{
|
|
|
|
gchar cmyk[4];
|
|
|
|
|
|
|
|
if (! g_input_stream_read_all (input, cmyk, sizeof (cmyk),
|
|
|
|
&bytes_read, NULL, error))
|
|
|
|
{
|
|
|
|
g_free (palette_entry);
|
|
|
|
g_free (full_palette_name);
|
2023-11-29 05:12:25 +08:00
|
|
|
g_object_unref (color);
|
2023-09-12 18:59:26 +08:00
|
|
|
|
|
|
|
g_printerr ("Invalid ACB palette colors");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (gint j = 0; j < 4; j++)
|
|
|
|
cmyk[j] = ((255 - cmyk[j]) / 2.55f) + 0.5f;
|
|
|
|
|
2023-11-29 05:12:25 +08:00
|
|
|
gegl_color_set_pixel (color, babl_format ("cmyk u8"), cmyk);
|
2023-09-12 18:59:26 +08:00
|
|
|
color_ok = TRUE;
|
|
|
|
}
|
|
|
|
else if (color_space == 7)
|
|
|
|
{
|
|
|
|
gchar lab[3];
|
|
|
|
|
|
|
|
if (! g_input_stream_read_all (input, lab, sizeof (lab),
|
|
|
|
&bytes_read, NULL, error))
|
|
|
|
{
|
|
|
|
g_free (palette_entry);
|
|
|
|
g_free (full_palette_name);
|
2023-11-29 05:12:25 +08:00
|
|
|
g_object_unref (color);
|
2023-09-12 18:59:26 +08:00
|
|
|
|
|
|
|
g_printerr ("Invalid ACB palette colors");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
lab[0] = (lab[0] / 2.55f) + 0.5f;
|
|
|
|
lab[1] = lab[1] - 128;
|
|
|
|
lab[2] = lab[2] - 128;
|
|
|
|
|
2023-11-29 05:12:25 +08:00
|
|
|
gegl_color_set_pixel (color, babl_format ("CIE Lab u8"), lab);
|
2023-09-12 18:59:26 +08:00
|
|
|
color_ok = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (color_ok && palette_entry)
|
2023-11-29 05:12:25 +08:00
|
|
|
gimp_palette_add_entry (palette, -1, full_palette_name, color);
|
2023-09-12 18:59:26 +08:00
|
|
|
|
|
|
|
g_free (palette_entry);
|
|
|
|
g_free (full_palette_name);
|
2023-11-29 05:12:25 +08:00
|
|
|
g_object_unref (color);
|
2023-09-12 18:59:26 +08:00
|
|
|
|
|
|
|
if (! color_ok)
|
|
|
|
{
|
|
|
|
g_printerr ("Invalid ACB palette colors");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
g_strfreev (palette_prefix);
|
|
|
|
g_strfreev (palette_suffix);
|
|
|
|
|
|
|
|
return g_list_prepend (NULL, palette);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gchar *
|
|
|
|
gimp_palette_load_acb_string (GInputStream *input,
|
|
|
|
goffset file_size,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
gint pal_name_len;
|
|
|
|
gunichar2 *pal_name = NULL;
|
|
|
|
gchar *pal_name_utf8;
|
|
|
|
goffset current_pos;
|
|
|
|
gsize bytes_read;
|
|
|
|
|
|
|
|
if (! g_input_stream_read_all (input, &pal_name_len, sizeof (pal_name_len),
|
|
|
|
&bytes_read, NULL, error))
|
|
|
|
{
|
|
|
|
g_printerr (_("Invalid ACB palette name."));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
pal_name_len = GUINT32_FROM_BE (pal_name_len);
|
|
|
|
current_pos = g_seekable_tell (G_SEEKABLE (input));
|
|
|
|
|
|
|
|
if (pal_name_len <= 0 || pal_name_len > (file_size - current_pos))
|
|
|
|
{
|
|
|
|
if (pal_name_len != 0)
|
|
|
|
g_printerr (_("Invalid ACB name size."));
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
pal_name = g_malloc (pal_name_len * 2);
|
|
|
|
|
|
|
|
for (gint i = 0; i < pal_name_len; i++)
|
|
|
|
{
|
|
|
|
if (! g_input_stream_read_all (input, &pal_name[i], 2,
|
|
|
|
&bytes_read, NULL, error))
|
|
|
|
{
|
|
|
|
g_printerr (_("Invalid ACB palette name."));
|
|
|
|
g_free (pal_name);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
pal_name[i] = GUINT16_FROM_BE (pal_name[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
pal_name_utf8 = g_utf16_to_utf8 (pal_name, pal_name_len, NULL, NULL, NULL);
|
|
|
|
g_free (pal_name);
|
|
|
|
|
|
|
|
return pal_name_utf8;
|
|
|
|
}
|
|
|
|
|
2023-08-28 00:51:02 +08:00
|
|
|
GList *
|
|
|
|
gimp_palette_load_ase (GimpContext *context,
|
|
|
|
GFile *file,
|
|
|
|
GInputStream *input,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
GimpPalette *palette;
|
|
|
|
gchar *palette_name;
|
|
|
|
goffset file_size;
|
|
|
|
gint num_cols;
|
|
|
|
gint i;
|
|
|
|
gchar header[8];
|
|
|
|
gshort group;
|
|
|
|
gsize bytes_read;
|
|
|
|
gboolean skip_first = FALSE;
|
|
|
|
const Babl *src_format = NULL;
|
2023-11-29 05:12:25 +08:00
|
|
|
gfloat pixels[4];
|
2023-08-28 00:51:02 +08:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
/* Get file size */
|
|
|
|
g_seekable_seek (G_SEEKABLE (input), 0, G_SEEK_END, NULL, error);
|
|
|
|
file_size = g_seekable_tell (G_SEEKABLE (input));
|
|
|
|
g_seekable_seek (G_SEEKABLE (input), 0, G_SEEK_SET, NULL, error);
|
|
|
|
|
|
|
|
if (! g_input_stream_read_all (input, header, sizeof (header),
|
|
|
|
&bytes_read, NULL, error) ||
|
|
|
|
bytes_read != sizeof (header))
|
|
|
|
{
|
2024-06-11 20:43:39 +08:00
|
|
|
g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
|
|
|
|
_("Could not read header from palette file '%s': "),
|
|
|
|
gimp_file_get_utf8_name (file));
|
2023-08-28 00:51:02 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Checking header values */
|
|
|
|
if (! g_str_has_prefix (header + 0, "ASEF") ||
|
|
|
|
header[5] != 0x01)
|
|
|
|
{
|
2024-06-11 20:43:39 +08:00
|
|
|
g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
|
|
|
|
_("Invalid ASE header: %s"),
|
|
|
|
gimp_file_get_utf8_name (file));
|
2023-08-28 00:51:02 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (! g_input_stream_read_all (input, &num_cols, sizeof (num_cols),
|
|
|
|
&bytes_read, NULL, error))
|
|
|
|
{
|
2024-06-11 20:43:39 +08:00
|
|
|
g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
|
|
|
|
_("Invalid number of colors in palette."));
|
2023-08-28 00:51:02 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
num_cols = GINT32_FROM_BE (num_cols);
|
|
|
|
if (num_cols <= 1)
|
|
|
|
{
|
2024-06-11 20:43:39 +08:00
|
|
|
g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
|
|
|
|
_("Invalid number of colors: %s."),
|
|
|
|
gimp_file_get_utf8_name (file));
|
2023-08-28 00:51:02 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* First block contains the palette name if
|
|
|
|
* one is defined. */
|
|
|
|
if (! g_input_stream_read_all (input, &group, sizeof (group),
|
|
|
|
&bytes_read, NULL, error))
|
|
|
|
{
|
2024-06-11 20:43:39 +08:00
|
|
|
g_set_error (error, GIMP_DATA_ERROR, GIMP_DATA_ERROR_READ,
|
|
|
|
_("Invalid ASE file: %s."),
|
|
|
|
gimp_file_get_utf8_name (file));
|
2023-08-28 00:51:02 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
group = GINT16_FROM_BE (group);
|
|
|
|
|
|
|
|
/* If first marker is 0x01, then the palette has no group name */
|
|
|
|
if (group != 1)
|
|
|
|
{
|
|
|
|
palette_name = gimp_palette_load_ase_block_name (input, file_size,
|
|
|
|
error);
|
|
|
|
palette = GIMP_PALETTE (gimp_palette_new (context, palette_name));
|
|
|
|
num_cols -= 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
palette_name = g_path_get_basename (gimp_file_get_utf8_name (file));
|
|
|
|
palette = GIMP_PALETTE (gimp_palette_new (context, palette_name));
|
|
|
|
skip_first = TRUE;
|
|
|
|
}
|
|
|
|
g_free (palette_name);
|
|
|
|
|
|
|
|
for (i = 0; i < num_cols; i++)
|
|
|
|
{
|
2023-11-29 05:12:25 +08:00
|
|
|
GeglColor *color;
|
|
|
|
gchar color_space[4];
|
|
|
|
gchar *color_name;
|
|
|
|
gshort spot_color;
|
|
|
|
gint components = 0;
|
|
|
|
gboolean valid_color = TRUE;
|
2023-08-28 00:51:02 +08:00
|
|
|
|
|
|
|
if (! skip_first)
|
|
|
|
{
|
|
|
|
if (! g_input_stream_read_all (input, &group, sizeof (group),
|
|
|
|
&bytes_read, NULL, error))
|
|
|
|
{
|
|
|
|
g_printerr ("Invalid ASE color entry: %s.",
|
|
|
|
gimp_file_get_utf8_name (file));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
skip_first = FALSE;
|
|
|
|
|
2023-11-24 14:08:09 +08:00
|
|
|
/* Skip group marker padding */
|
|
|
|
group = GINT16_FROM_BE (group);
|
|
|
|
if (group < 0)
|
|
|
|
{
|
|
|
|
gchar marker[4];
|
|
|
|
|
|
|
|
if (! g_input_stream_read_all (input, &marker, sizeof (marker),
|
|
|
|
&bytes_read, NULL, error))
|
|
|
|
{
|
|
|
|
g_printerr ("Invalid ASE group marker: %s.",
|
|
|
|
gimp_file_get_utf8_name (file));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
num_cols--;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-08-28 00:51:02 +08:00
|
|
|
color_name = gimp_palette_load_ase_block_name (input, file_size, error);
|
|
|
|
if (! color_name)
|
|
|
|
break;
|
|
|
|
|
|
|
|
g_input_stream_read_all (input, color_space, sizeof (color_space),
|
|
|
|
&bytes_read, NULL, error);
|
|
|
|
|
|
|
|
/* Color formats */
|
2023-09-07 04:15:59 +08:00
|
|
|
if (g_str_has_prefix (g_strstrip (color_space), "RGB"))
|
2023-08-28 00:51:02 +08:00
|
|
|
{
|
|
|
|
components = 3;
|
|
|
|
src_format = babl_format ("R'G'B' float");
|
|
|
|
}
|
2023-09-07 04:15:59 +08:00
|
|
|
else if (g_str_has_prefix (g_strstrip (color_space), "GRAY"))
|
2023-08-28 00:51:02 +08:00
|
|
|
{
|
|
|
|
components = 1;
|
|
|
|
src_format = babl_format ("Y' float");
|
|
|
|
}
|
2023-09-07 04:15:59 +08:00
|
|
|
else if (g_str_has_prefix (g_strstrip (color_space), "CMYK"))
|
2023-08-28 00:51:02 +08:00
|
|
|
{
|
|
|
|
components = 4;
|
|
|
|
src_format = babl_format ("CMYK float");
|
|
|
|
}
|
2023-09-07 04:15:59 +08:00
|
|
|
else if (g_str_has_prefix (g_strstrip (color_space), "LAB"))
|
2023-08-28 00:51:02 +08:00
|
|
|
{
|
|
|
|
components = 3;
|
|
|
|
src_format = babl_format ("CIE Lab float");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (components == 0)
|
|
|
|
{
|
|
|
|
g_printerr (_("Invalid color components: %s."), color_space);
|
|
|
|
g_free (color_name);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (gint j = 0; j < components; j++)
|
|
|
|
{
|
2023-11-24 14:08:09 +08:00
|
|
|
gint32 tmp;
|
2023-08-28 00:51:02 +08:00
|
|
|
|
|
|
|
if (! g_input_stream_read_all (input, &tmp, sizeof (tmp),
|
|
|
|
&bytes_read, NULL, error))
|
|
|
|
{
|
|
|
|
g_printerr (_("Invalid ASE color entry: %s."),
|
|
|
|
gimp_file_get_utf8_name (file));
|
|
|
|
g_free (color_name);
|
|
|
|
valid_color = FALSE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Convert 4 bytes to a 32bit float value */
|
|
|
|
tmp = GINT32_FROM_BE (tmp);
|
2023-11-19 21:53:18 +08:00
|
|
|
memcpy (&pixels[j], &tmp, 4);
|
2023-08-28 00:51:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (! valid_color)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* The L component of LAB goes from 0 to 100 percent */
|
|
|
|
if (g_str_has_prefix (color_space, "LAB"))
|
|
|
|
pixels[0] *= 100;
|
|
|
|
|
|
|
|
/* TODO: When GIMP supports spot colors, use this information in
|
|
|
|
* the palette. */
|
|
|
|
if (! g_input_stream_read_all (input, &spot_color, sizeof (spot_color),
|
|
|
|
&bytes_read, NULL, error))
|
|
|
|
{
|
|
|
|
g_printerr (_("Invalid ASE color entry: %s."),
|
|
|
|
gimp_file_get_utf8_name (file));
|
|
|
|
g_free (color_name);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2023-11-29 05:12:25 +08:00
|
|
|
color = gegl_color_new (NULL);
|
|
|
|
gegl_color_set_pixel (color, src_format, pixels);
|
|
|
|
|
|
|
|
gimp_palette_add_entry (palette, -1, color_name, color);
|
2023-08-28 00:51:02 +08:00
|
|
|
g_free (color_name);
|
2023-11-29 05:12:25 +08:00
|
|
|
g_object_unref (color);
|
2023-08-28 00:51:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return g_list_prepend (NULL, palette);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gchar *
|
|
|
|
gimp_palette_load_ase_block_name (GInputStream *input,
|
|
|
|
goffset file_size,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
gint block_length;
|
|
|
|
gushort pal_name_len;
|
|
|
|
gunichar2 *pal_name = NULL;
|
|
|
|
gchar *pal_name_utf8;
|
|
|
|
goffset current_pos;
|
|
|
|
gsize bytes_read;
|
|
|
|
|
|
|
|
if (! g_input_stream_read_all (input, &block_length, sizeof (block_length),
|
|
|
|
&bytes_read, NULL, error))
|
|
|
|
{
|
|
|
|
g_printerr (_("Invalid ASE palette name."));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
block_length = GINT32_FROM_BE (block_length);
|
|
|
|
current_pos = g_seekable_tell (G_SEEKABLE (input));
|
|
|
|
|
|
|
|
if (block_length <= 0 || block_length > (file_size - current_pos))
|
|
|
|
{
|
|
|
|
g_printerr (_("Invalid ASE block size."));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (! g_input_stream_read_all (input, &pal_name_len, sizeof (pal_name_len),
|
|
|
|
&bytes_read, NULL, error))
|
|
|
|
{
|
|
|
|
g_printerr (_("Invalid ASE palette name."));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
pal_name_len = GUINT16_FROM_BE (pal_name_len);
|
|
|
|
current_pos = g_seekable_tell (G_SEEKABLE (input));
|
|
|
|
|
|
|
|
if (pal_name_len <= 0 || pal_name_len > (file_size - current_pos))
|
|
|
|
{
|
|
|
|
g_printerr (_("Invalid ASE name size."));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
pal_name = g_malloc (pal_name_len * 2);
|
|
|
|
|
|
|
|
for (gint i = 0; i < pal_name_len; i++)
|
|
|
|
{
|
|
|
|
if (! g_input_stream_read_all (input, &pal_name[i], 2,
|
|
|
|
&bytes_read, NULL, error))
|
|
|
|
{
|
|
|
|
g_printerr (_("Invalid ASE palette name."));
|
|
|
|
g_free (pal_name);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
pal_name[i] = GUINT16_FROM_BE (pal_name[i]);
|
|
|
|
}
|
|
|
|
|
2023-09-13 10:36:05 +08:00
|
|
|
pal_name_utf8 = g_utf16_to_utf8 (pal_name, pal_name_len, NULL, NULL, NULL);
|
2023-08-28 00:51:02 +08:00
|
|
|
g_free (pal_name);
|
|
|
|
|
|
|
|
return pal_name_utf8;
|
|
|
|
}
|
2007-12-19 01:01:19 +08:00
|
|
|
|
|
|
|
GList *
|
2014-07-03 23:36:01 +08:00
|
|
|
gimp_palette_load_css (GimpContext *context,
|
|
|
|
GFile *file,
|
|
|
|
GInputStream *input,
|
|
|
|
GError **error)
|
2007-12-19 01:01:19 +08:00
|
|
|
{
|
2014-07-03 23:36:01 +08:00
|
|
|
GimpPalette *palette;
|
|
|
|
GDataInputStream *data_input;
|
|
|
|
gchar *name;
|
|
|
|
GRegex *regex;
|
|
|
|
gchar *buf;
|
2007-12-19 01:01:19 +08:00
|
|
|
|
2014-07-01 20:25:37 +08:00
|
|
|
g_return_val_if_fail (G_IS_FILE (file), NULL);
|
2018-06-10 13:43:57 +08:00
|
|
|
g_return_val_if_fail (G_IS_INPUT_STREAM (input), NULL);
|
2007-12-19 01:01:19 +08:00
|
|
|
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
|
|
|
|
2023-02-20 02:45:47 +08:00
|
|
|
regex = g_regex_new (".*color.*:(?P<param>.*)", G_REGEX_CASELESS, 0, error);
|
2007-12-19 01:01:19 +08:00
|
|
|
if (! regex)
|
|
|
|
return NULL;
|
|
|
|
|
2014-07-01 20:25:37 +08:00
|
|
|
name = g_path_get_basename (gimp_file_get_utf8_name (file));
|
2010-04-11 01:55:42 +08:00
|
|
|
palette = GIMP_PALETTE (gimp_palette_new (context, name));
|
2007-12-19 01:01:19 +08:00
|
|
|
g_free (name);
|
|
|
|
|
2014-07-03 23:36:01 +08:00
|
|
|
data_input = g_data_input_stream_new (input);
|
|
|
|
|
2007-12-19 01:01:19 +08:00
|
|
|
do
|
|
|
|
{
|
2014-07-03 23:36:01 +08:00
|
|
|
gsize buf_len = 1024;
|
2007-12-19 01:01:19 +08:00
|
|
|
|
2014-07-03 23:36:01 +08:00
|
|
|
buf = g_data_input_stream_read_line (data_input, &buf_len, NULL, NULL);
|
|
|
|
|
|
|
|
if (buf)
|
2008-11-07 17:32:23 +08:00
|
|
|
{
|
2014-07-03 23:36:01 +08:00
|
|
|
GMatchInfo *matches;
|
|
|
|
|
2008-11-07 17:32:23 +08:00
|
|
|
if (g_regex_match (regex, buf, 0, &matches))
|
|
|
|
{
|
2023-11-29 05:12:25 +08:00
|
|
|
GeglColor *color;
|
|
|
|
gchar *word = g_match_info_fetch_named (matches, "param");
|
2007-12-19 01:01:19 +08:00
|
|
|
|
2024-04-20 18:24:52 +08:00
|
|
|
color = gimp_color_parse_css (word);
|
2023-11-29 05:12:25 +08:00
|
|
|
if (color)
|
2008-11-07 17:32:23 +08:00
|
|
|
{
|
2023-11-13 04:30:07 +08:00
|
|
|
if (! gimp_palette_find_entry (palette, color, NULL))
|
2023-11-29 05:12:25 +08:00
|
|
|
gimp_palette_add_entry (palette, -1, NULL, color);
|
2023-11-13 04:30:07 +08:00
|
|
|
|
|
|
|
g_object_unref (color);
|
2008-11-07 17:32:23 +08:00
|
|
|
}
|
2007-12-19 01:01:19 +08:00
|
|
|
|
2008-11-07 17:32:23 +08:00
|
|
|
g_free (word);
|
|
|
|
}
|
2017-11-26 11:01:19 +08:00
|
|
|
g_match_info_free (matches);
|
2014-07-03 23:36:01 +08:00
|
|
|
g_free (buf);
|
2008-11-07 17:32:23 +08:00
|
|
|
}
|
2014-07-03 23:36:01 +08:00
|
|
|
}
|
|
|
|
while (buf);
|
2007-12-19 01:01:19 +08:00
|
|
|
|
|
|
|
g_regex_unref (regex);
|
2014-07-03 23:36:01 +08:00
|
|
|
g_object_unref (data_input);
|
2007-12-19 01:01:19 +08:00
|
|
|
|
|
|
|
return g_list_prepend (NULL, palette);
|
|
|
|
}
|
|
|
|
|
2023-02-19 21:46:17 +08:00
|
|
|
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];
|
2023-11-29 05:12:25 +08:00
|
|
|
GeglColor *color = NULL;
|
2023-02-19 21:46:17 +08:00
|
|
|
const Babl *src_format = NULL;
|
|
|
|
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"))
|
|
|
|
{
|
2023-11-29 05:12:25 +08:00
|
|
|
src_format = babl_format_with_space ("R'G'B' float", NULL);
|
2023-02-19 21:46:17 +08:00
|
|
|
}
|
|
|
|
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)
|
|
|
|
{
|
2023-11-29 05:12:25 +08:00
|
|
|
color = gegl_color_new (NULL);
|
|
|
|
gegl_color_set_pixel (color, src_format, true_values);
|
2023-02-19 21:46:17 +08:00
|
|
|
}
|
|
|
|
|
2023-11-29 05:12:25 +08:00
|
|
|
if (color)
|
2023-02-19 21:46:17 +08:00
|
|
|
{
|
|
|
|
gimp_palette_add_entry (sbz_data->palette, sbz_data->position,
|
2023-11-29 05:12:25 +08:00
|
|
|
NULL, color);
|
2023-02-19 21:46:17 +08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-10-03 22:54:07 +08:00
|
|
|
GimpPaletteFileFormat
|
2014-07-03 22:27:05 +08:00
|
|
|
gimp_palette_load_detect_format (GFile *file,
|
|
|
|
GInputStream *input)
|
2006-10-03 22:54:07 +08:00
|
|
|
{
|
|
|
|
GimpPaletteFileFormat format = GIMP_PALETTE_FILE_FORMAT_UNKNOWN;
|
|
|
|
gchar header[16];
|
2014-07-03 22:27:05 +08:00
|
|
|
gsize bytes_read;
|
2006-10-03 22:54:07 +08:00
|
|
|
|
2014-07-03 22:27:05 +08:00
|
|
|
if (g_input_stream_read_all (input, &header, sizeof (header),
|
|
|
|
&bytes_read, NULL, NULL) &&
|
|
|
|
bytes_read == sizeof (header))
|
2006-10-03 22:54:07 +08:00
|
|
|
{
|
2013-09-15 14:46:28 +08:00
|
|
|
if (g_str_has_prefix (header + 0, "RIFF") &&
|
2023-11-29 05:12:25 +08:00
|
|
|
/* TODO: only the Simple PAL format is supported right now.
|
|
|
|
* Extended PAL Format with "PAL plth" header support could be added
|
|
|
|
* later on.
|
|
|
|
*/
|
2013-09-15 14:46:28 +08:00
|
|
|
g_str_has_prefix (header + 8, "PAL data"))
|
2006-10-03 22:54:07 +08:00
|
|
|
{
|
2013-09-15 14:46:28 +08:00
|
|
|
format = GIMP_PALETTE_FILE_FORMAT_RIFF_PAL;
|
2006-10-03 22:54:07 +08:00
|
|
|
}
|
2013-09-15 14:46:28 +08:00
|
|
|
else if (g_str_has_prefix (header, "GIMP Palette"))
|
2007-08-07 21:42:55 +08:00
|
|
|
{
|
2013-09-15 14:46:28 +08:00
|
|
|
format = GIMP_PALETTE_FILE_FORMAT_GPL;
|
|
|
|
}
|
|
|
|
else if (g_str_has_prefix (header, "JASC-PAL"))
|
|
|
|
{
|
|
|
|
format = GIMP_PALETTE_FILE_FORMAT_PSP_PAL;
|
|
|
|
}
|
2023-09-12 18:59:26 +08:00
|
|
|
else if (g_str_has_prefix (header, "8BCB"))
|
|
|
|
{
|
|
|
|
format = GIMP_PALETTE_FILE_FORMAT_ACB;
|
|
|
|
}
|
2013-09-15 14:46:28 +08:00
|
|
|
}
|
2007-08-07 21:42:55 +08:00
|
|
|
|
2013-09-15 14:46:28 +08:00
|
|
|
if (format == GIMP_PALETTE_FILE_FORMAT_UNKNOWN)
|
|
|
|
{
|
2014-07-03 22:27:05 +08:00
|
|
|
gchar *lower = g_ascii_strdown (gimp_file_get_utf8_name (file), -1);
|
2007-08-07 21:42:55 +08:00
|
|
|
|
2014-07-03 22:27:05 +08:00
|
|
|
if (g_str_has_suffix (lower, ".aco"))
|
2013-09-15 14:46:28 +08:00
|
|
|
{
|
|
|
|
format = GIMP_PALETTE_FILE_FORMAT_ACO;
|
2007-08-07 21:42:55 +08:00
|
|
|
}
|
2023-08-28 00:51:02 +08:00
|
|
|
if (g_str_has_suffix (lower, ".ase"))
|
|
|
|
{
|
|
|
|
format = GIMP_PALETTE_FILE_FORMAT_ASE;
|
|
|
|
}
|
2014-07-03 22:27:05 +08:00
|
|
|
else if (g_str_has_suffix (lower, ".css"))
|
2006-10-03 22:54:07 +08:00
|
|
|
{
|
2013-09-15 14:46:28 +08:00
|
|
|
format = GIMP_PALETTE_FILE_FORMAT_CSS;
|
2006-10-03 22:54:07 +08:00
|
|
|
}
|
2023-02-19 21:46:17 +08:00
|
|
|
else if (g_str_has_suffix (lower, ".sbz"))
|
|
|
|
{
|
|
|
|
format = GIMP_PALETTE_FILE_FORMAT_SBZ;
|
|
|
|
}
|
2006-10-03 22:54:07 +08:00
|
|
|
|
2014-07-03 22:27:05 +08:00
|
|
|
g_free (lower);
|
2013-09-15 14:46:28 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (format == GIMP_PALETTE_FILE_FORMAT_UNKNOWN)
|
|
|
|
{
|
2014-07-03 22:27:05 +08:00
|
|
|
GFileInfo *info = g_file_query_info (file,
|
|
|
|
G_FILE_ATTRIBUTE_STANDARD_SIZE,
|
|
|
|
G_FILE_QUERY_INFO_NONE,
|
|
|
|
NULL, NULL);
|
2013-09-15 14:46:28 +08:00
|
|
|
|
2014-07-03 22:27:05 +08:00
|
|
|
if (info)
|
2013-09-15 14:46:28 +08:00
|
|
|
{
|
2023-09-19 20:38:42 +08:00
|
|
|
goffset size = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_STANDARD_SIZE);
|
2014-07-03 22:27:05 +08:00
|
|
|
|
2023-11-29 05:12:25 +08:00
|
|
|
/* TODO: the file can optionally be 772 bytes long.
|
|
|
|
* See: https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/
|
|
|
|
* Section: "Color Table "
|
|
|
|
*/
|
2014-07-03 22:27:05 +08:00
|
|
|
if (size == 768)
|
2013-09-15 14:46:28 +08:00
|
|
|
format = GIMP_PALETTE_FILE_FORMAT_ACT;
|
2014-07-03 22:27:05 +08:00
|
|
|
|
|
|
|
g_object_unref (info);
|
2013-09-15 14:46:28 +08:00
|
|
|
}
|
2006-10-03 22:54:07 +08:00
|
|
|
}
|
|
|
|
|
2014-07-03 22:27:05 +08:00
|
|
|
g_seekable_seek (G_SEEKABLE (input), 0, G_SEEK_SET, NULL, NULL);
|
2013-09-25 04:14:10 +08:00
|
|
|
|
2006-10-03 22:54:07 +08:00
|
|
|
return format;
|
|
|
|
}
|