plug-ins: Add method to load external PSD metadata

Creates a new public procedure that can be used by JPEG/TIFF files to
load any PSD-formatted metadata they have. This consolidates code
to the PSD plug-in, and lets JPEG/TIFF get immediate updates as the
PSD plug-in improves its own metadata support.
Note that only Macintosh formatted metadata is currently supported
by the PSD plug-in; IBM PC formatted metadata is reversed and not
yet interpreted.
This commit is contained in:
Alx Sa 2022-12-19 16:25:31 +00:00
parent 8bd07e468b
commit b788513bcc
4 changed files with 257 additions and 6 deletions

View File

@ -57,6 +57,10 @@ static PSDlayer ** read_layer_block (PSDimage *img_a,
GInputStream *input, GInputStream *input,
GError **error); GError **error);
static PSDlayer ** read_layer_info (PSDimage *img_a,
GInputStream *input,
GError **error);
static gint read_merged_image_block (PSDimage *img_a, static gint read_merged_image_block (PSDimage *img_a,
GInputStream *input, GInputStream *input,
GError **error); GError **error);
@ -205,6 +209,7 @@ load_image (GFile *file,
/* ----- Read the PSD file Layer & Mask block ----- */ /* ----- Read the PSD file Layer & Mask block ----- */
IFDBG(2) g_debug ("Read layer & mask block at offset %" G_GOFFSET_FORMAT, IFDBG(2) g_debug ("Read layer & mask block at offset %" G_GOFFSET_FORMAT,
PSD_TELL(input)); PSD_TELL(input));
img_a.mask_layer_len = 0;
lyr_a = read_layer_block (&img_a, input, &error); lyr_a = read_layer_block (&img_a, input, &error);
if (merged_image_only) if (merged_image_only)
@ -297,6 +302,137 @@ load_image (GFile *file,
return NULL; return NULL;
} }
/* Loading metadata for external file formats */
GimpImage * load_image_metadata (GFile *file,
gint data_length,
GimpImage *image,
gboolean for_layers,
gboolean is_cmyk,
PSDSupport *unsupported_features,
GError **error)
{
GInputStream *input;
PSDimage img_a;
gboolean profile_loaded;
gboolean resolution_loaded;
/* Convert metadata file to PSD format */
input = G_INPUT_STREAM (g_file_read (file, NULL, error));
if (! input)
{
g_object_unref (input);
return image;
}
/* Load metadata for external file format */
img_a.image_res_len = data_length;
img_a.image_res_start = 0;
img_a.version = 1;
img_a.layer_selection = NULL;
img_a.columns = gimp_image_get_width (image);
img_a.rows = gimp_image_get_height(image);
img_a.base_type = gimp_image_get_base_type (image);
img_a.merged_image_only = FALSE;
img_a.alpha_names = NULL;
initialize_unsupported (unsupported_features);
img_a.unsupported_features = unsupported_features;
if (! for_layers)
{
PSDimageres res_a;
while (PSD_TELL (input) < img_a.image_res_start + img_a.image_res_len)
{
if (get_image_resource_header (&res_a, input, error) < 0)
break;
if (res_a.data_start + res_a.data_len >
img_a.image_res_start + img_a.image_res_len)
{
IFDBG(1) g_debug ("Unexpected end of image resource data");
break;
}
if (load_image_resource (&res_a, image, &img_a, input,
&profile_loaded, &resolution_loaded,
error) < 0)
break;
}
}
else
{
PSDlayer **lyr_a = NULL;
guint64 skip;
gchar key[4];
/* Skip the first 8 bytes to get it in the correct
* format for the layer block */
if (! psd_read_len (input, &skip, img_a.version, error))
{
g_object_unref (input);
return image;
}
if (psd_read (input, &key, 4, error) < 4)
{
g_object_unref (input);
return image;
}
/* Setting up PSDImage structure */
if (memcmp (key, "Layr", 4) == 0)
{
img_a.bps = 8;
}
else if (memcmp (key, "Lr16", 4) == 0)
{
img_a.bps = 16;
}
else if (memcmp (key, "Lr32", 4) == 0)
{
img_a.bps = 32;
}
else
{
g_object_unref (input);
return image;
}
switch (gimp_image_get_base_type (image))
{
case GIMP_RGB:
img_a.color_mode = PSD_RGB;
break;
case GIMP_GRAY:
img_a.color_mode = PSD_GRAYSCALE;
break;
case GIMP_INDEXED:
img_a.color_mode = PSD_INDEXED;
break;
}
if (is_cmyk)
img_a.color_mode = PSD_CMYK;
/* Set layer block size from metadata */
img_a.mask_layer_len = data_length;
lyr_a = read_layer_block (&img_a, input, error);
if (! lyr_a)
{
g_object_unref (input);
return image;
}
add_layers (image, &img_a, lyr_a, input, error);
}
g_object_unref (input);
return image;
}
/* Local functions */ /* Local functions */
@ -1082,13 +1218,20 @@ read_layer_block (PSDimage *img_a,
guint64 block_end; guint64 block_end;
gint block_len_size = (img_a->version == 1 ? 4 : 8); gint block_len_size = (img_a->version == 1 ? 4 : 8);
/* If layer data is being loaded for non-PSD files (like TIFF),
* then mask_layer_len will have its size preloaded */
if (img_a->mask_layer_len == 0)
{
if (! psd_read_len (input, &block_len, img_a->version, error)) if (! psd_read_len (input, &block_len, img_a->version, error))
{ {
img_a->num_layers = -1; img_a->num_layers = -1;
return NULL; return NULL;
} }
else else
{
img_a->mask_layer_len = block_len; img_a->mask_layer_len = block_len;
}
}
IFDBG(1) g_debug ("Layer and mask block size = %" G_GOFFSET_FORMAT, img_a->mask_layer_len); IFDBG(1) g_debug ("Layer and mask block size = %" G_GOFFSET_FORMAT, img_a->mask_layer_len);

View File

@ -29,6 +29,15 @@ GimpImage * load_image (GFile *file,
PSDSupport *unsupported_features, PSDSupport *unsupported_features,
GError **error); GError **error);
GimpImage * load_image_metadata
(GFile *file,
gint data_length,
GimpImage *image,
gboolean for_layers,
gboolean is_cmyk,
PSDSupport *unsupported_features,
GError **error);
void load_dialog (PSDSupport *unsupported_features); void load_dialog (PSDSupport *unsupported_features);

View File

@ -74,6 +74,11 @@ static GimpValueArray * psd_save (GimpProcedure *procedure,
GFile *file, GFile *file,
const GimpValueArray *args, const GimpValueArray *args,
gpointer run_data); gpointer run_data);
static GimpValueArray * psd_load_metadata (GimpProcedure *procedure,
GimpRunMode run_mode,
GFile *file,
const GimpValueArray *args,
gpointer run_data);
G_DEFINE_TYPE (Psd, psd, GIMP_TYPE_PLUG_IN) G_DEFINE_TYPE (Psd, psd, GIMP_TYPE_PLUG_IN)
@ -106,6 +111,7 @@ psd_query_procedures (GimpPlugIn *plug_in)
list = g_list_append (list, g_strdup (LOAD_PROC)); list = g_list_append (list, g_strdup (LOAD_PROC));
list = g_list_append (list, g_strdup (LOAD_MERGED_PROC)); list = g_list_append (list, g_strdup (LOAD_MERGED_PROC));
list = g_list_append (list, g_strdup (SAVE_PROC)); list = g_list_append (list, g_strdup (SAVE_PROC));
list = g_list_append (list, g_strdup (LOAD_METADATA_PROC));
return list; return list;
} }
@ -258,6 +264,46 @@ psd_create_procedure (GimpPlugIn *plug_in,
FALSE, FALSE,
G_PARAM_READWRITE); G_PARAM_READWRITE);
} }
else if (! strcmp (name, LOAD_METADATA_PROC))
{
procedure = gimp_load_procedure_new (plug_in, name,
GIMP_PDB_PROC_TYPE_PLUGIN,
psd_load_metadata, NULL, NULL);
gimp_procedure_set_documentation (procedure,
"Loads Photoshop-format metadata "
"from other file formats.",
"Loads Photoshop-format metadata "
"from other file formats.",
name);
gimp_procedure_set_attribution (procedure,
"John Marshall",
"John Marshall",
"2007");
GIMP_PROC_ARG_INT (procedure, "size",
"Metadata size",
NULL,
0, G_MAXINT, 0,
G_PARAM_READWRITE);
gimp_procedure_add_argument (procedure,
gimp_param_spec_image ("image",
"image",
"The image",
FALSE,
GIMP_PARAM_READWRITE));
GIMP_PROC_ARG_BOOLEAN (procedure, "metadata-type",
"Metadata type",
"If the metadata contains image or "
"layer PSD resources.",
FALSE,
G_PARAM_READWRITE);
GIMP_PROC_ARG_BOOLEAN (procedure, "cmyk",
"CMYK",
"If the layer metadata needs to be "
"converted from CMYK colorspace.",
FALSE,
G_PARAM_READWRITE);
}
return procedure; return procedure;
} }
@ -453,3 +499,55 @@ psd_save (GimpProcedure *procedure,
return gimp_procedure_new_return_values (procedure, status, error); return gimp_procedure_new_return_values (procedure, status, error);
} }
static GimpValueArray *
psd_load_metadata (GimpProcedure *procedure,
GimpRunMode run_mode,
GFile *file,
const GimpValueArray *args,
gpointer run_data)
{
GimpValueArray *return_vals;
GimpImage *image;
gint data_length;
PSDSupport unsupported_features;
gboolean is_layer = FALSE;
gboolean is_cmyk = FALSE;
GError *error = NULL;
gegl_init (NULL, NULL);
/* Retrieve image */
if (gimp_value_array_length (args) > 1)
{
data_length = g_value_get_int (gimp_value_array_index (args, 0));
image = g_value_get_object (gimp_value_array_index (args, 1));
}
else
{
return gimp_procedure_new_return_values (procedure,
GIMP_PDB_EXECUTION_ERROR,
error);
}
if (gimp_value_array_length (args) > 2)
is_layer = g_value_get_boolean (gimp_value_array_index (args, 2));
if (gimp_value_array_length (args) > 3)
is_cmyk = g_value_get_boolean (gimp_value_array_index (args, 3));
image = load_image_metadata (file, data_length, image, is_layer, is_cmyk,
&unsupported_features, &error);
if (! image)
return gimp_procedure_new_return_values (procedure,
GIMP_PDB_EXECUTION_ERROR,
error);
return_vals = gimp_procedure_new_return_values (procedure,
GIMP_PDB_SUCCESS,
NULL);
GIMP_VALUES_SET_IMAGE (return_vals, 1, image);
return return_vals;
}

View File

@ -35,6 +35,7 @@
#define LOAD_MERGED_PROC "file-psd-load-merged" #define LOAD_MERGED_PROC "file-psd-load-merged"
#define LOAD_THUMB_PROC "file-psd-load-thumb" #define LOAD_THUMB_PROC "file-psd-load-thumb"
#define SAVE_PROC "file-psd-save" #define SAVE_PROC "file-psd-save"
#define LOAD_METADATA_PROC "file-psd-load-metadata"
#define PLUG_IN_BINARY "file-psd" #define PLUG_IN_BINARY "file-psd"
#define PLUG_IN_ROLE "gimp-file-psd" #define PLUG_IN_ROLE "gimp-file-psd"