plug-ins: Show unsupported PSD features in GUI

Adds a new PSDSupport struct to keep track of what unsupported features
a PSD contains.
It is then used to conditionally display a compatibility notice
via a GUI.
This commit is contained in:
Alx Sa 2023-01-23 04:05:53 +00:00
parent 2c533abe9f
commit 1d45fc0808
6 changed files with 285 additions and 40 deletions

View File

@ -419,6 +419,12 @@ load_image_resource (PSDimageres *res_a,
load_resource_2999 (res_a, image, input, error);
break;
case PSD_LAYER_COMPS:
img_a->unsupported_features->layer_comp = TRUE;
img_a->unsupported_features->show_gui = TRUE;
load_resource_unknown (res_a, image, input, error);
break;
default:
if (res_a->id >= 2000 &&
res_a->id < 2999)

View File

@ -102,13 +102,15 @@
* New stuff temporarily until I can get them sorted out *
* Placed Layer *
PSD_LPL_PLACE_LAYER "plLd" - * Placed layer (?) *
PSD_LPL_PLACE_LAYER "PlLd" - * Placed layer (?) (based on PSD files, not specification) *
PSD_LPL_PLACE_LAYER_NEW "SoLd" - * Placed layer (PS10) *
PSD_SMART_OBJECT_LAYER "SoLE" - * Smart Object Layer (CC2015) *
* Linked Layer *
PSD_LLL_LINKED_LAYER "lnkD" - * Linked layer (?) *
PSD_LLL_LINKED_LAYER_2 "lnk2" - * Linked layer 2nd key *
PSD_LLL_LINKED_LAYER_3 "lnk3" - * Linked layer 3rd key *
PSD_LLL_LINKED_LAYER_EXT "lnkE" - * Linked layer external *
* Merged Transparency *
PSD_LMT_MERGE_TRANS "Mtrn" - * Merged transparency save flag (?) *
@ -298,45 +300,142 @@ load_layer_resource (PSDlayerres *res_a,
|| memcmp (res_a->key, PSD_LADJ_THRESHOLD, 4) == 0
|| memcmp (res_a->key, PSD_LADJ_INVERT, 4) == 0
|| memcmp (res_a->key, PSD_LADJ_POSTERIZE, 4) == 0)
load_resource_ladj (res_a, lyr_a, input, error);
{
if (lyr_a)
{
lyr_a->unsupported_features->adjustment_layer = TRUE;
lyr_a->unsupported_features->show_gui = TRUE;
}
load_resource_ladj (res_a, lyr_a, input, error);
}
else if (memcmp (res_a->key, PSD_LFIL_SOLID, 4) == 0
|| memcmp (res_a->key, PSD_LFIL_PATTERN, 4) == 0
|| memcmp (res_a->key, PSD_LFIL_GRADIENT, 4) == 0)
load_resource_lfil (res_a, lyr_a, input, error);
{
if (lyr_a)
{
lyr_a->unsupported_features->fill_layer = TRUE;
lyr_a->unsupported_features->show_gui = TRUE;
}
load_resource_lfil (res_a, lyr_a, input, error);
}
else if (memcmp (res_a->key, PSD_LFX_FX, 4) == 0
|| memcmp (res_a->key, PSD_LFX_FX2, 4) == 0)
load_resource_lfx (res_a, lyr_a, input, error);
{
if (lyr_a)
{
lyr_a->unsupported_features->layer_effect = TRUE;
lyr_a->unsupported_features->show_gui = TRUE;
}
load_resource_lfx (res_a, lyr_a, input, error);
}
else if (memcmp (res_a->key, PSD_LTYP_TYPE, 4) == 0
|| memcmp (res_a->key, PSD_LTYP_TYPE2, 4) == 0)
load_resource_ltyp (res_a, lyr_a, input, error);
{
if (lyr_a)
{
lyr_a->unsupported_features->text_layer = TRUE;
lyr_a->unsupported_features->show_gui = TRUE;
}
load_resource_ltyp (res_a, lyr_a, input, error);
}
else if (memcmp (res_a->key, PSD_LPRP_UNICODE, 4) == 0)
load_resource_luni (res_a, lyr_a, input, error);
{
load_resource_luni (res_a, lyr_a, input, error);
}
else if (memcmp (res_a->key, PSD_LPRP_ID, 4) == 0)
load_resource_lyid (res_a, lyr_a, input, error);
{
load_resource_lyid (res_a, lyr_a, input, error);
}
else if (memcmp (res_a->key, PSD_LPRP_COLOR, 4) == 0)
load_resource_lclr (res_a, lyr_a, input, error);
{
load_resource_lclr (res_a, lyr_a, input, error);
}
else if (memcmp (res_a->key, PSD_LOTH_SECTION, 4) == 0
|| memcmp (res_a->key, PSD_LOTH_SECTION2, 4) == 0) /* bug #789981 */
load_resource_lsct (res_a, lyr_a, input, error);
{
load_resource_lsct (res_a, lyr_a, input, error);
}
else if (memcmp (res_a->key, PSD_LFX_FX, 4) == 0)
load_resource_lrfx (res_a, lyr_a, input, error);
{
load_resource_lrfx (res_a, lyr_a, input, error);
}
else if (memcmp (res_a->key, PSD_LPRP_VERSION, 4) == 0)
load_resource_lyvr (res_a, lyr_a, input, error);
{
load_resource_lyvr (res_a, lyr_a, input, error);
}
else if (memcmp (res_a->key, PSD_LPRP_SOURCE, 4) == 0)
load_resource_lnsr (res_a, lyr_a, input, error);
{
load_resource_lnsr (res_a, lyr_a, input, error);
}
else if (memcmp (res_a->key, PSD_LOTH_VECTOR_STROKE, 4) == 0)
{
if (lyr_a)
{
lyr_a->unsupported_features->stroke = TRUE;
lyr_a->unsupported_features->show_gui = TRUE;
}
load_resource_unknown (res_a, lyr_a, input, error);
}
else if (memcmp (res_a->key, PSD_LMSK_VMASK, 4) == 0)
{
if (lyr_a)
{
lyr_a->unsupported_features->vector_mask = TRUE;
lyr_a->unsupported_features->show_gui = TRUE;
}
load_resource_unknown (res_a, lyr_a, input, error);
}
else if (memcmp (res_a->key, PSD_SMART_OBJECT_LAYER, 4) == 0
|| memcmp (res_a->key, PSD_LPL_PLACE_LAYER, 4) == 0
|| memcmp (res_a->key, PSD_LPL_PLACE_LAYER_NEW, 4) == 0)
{
if (lyr_a)
{
lyr_a->unsupported_features->smart_object = TRUE;
lyr_a->unsupported_features->show_gui = TRUE;
}
load_resource_unknown (res_a, lyr_a, input, error);
}
else if (memcmp (res_a->key, PSD_LLL_LINKED_LAYER, 4) == 0
|| memcmp (res_a->key, PSD_LLL_LINKED_LAYER_2, 4) == 0
|| memcmp (res_a->key, PSD_LLL_LINKED_LAYER_3, 4) == 0
|| memcmp (res_a->key, PSD_LLL_LINKED_LAYER_EXT, 4) == 0)
{
if (lyr_a)
{
lyr_a->unsupported_features->linked_layer = TRUE;
lyr_a->unsupported_features->show_gui = TRUE;
}
load_resource_unknown (res_a, lyr_a, input, error);
}
else
load_resource_unknown (res_a, lyr_a, input, error);
{
load_resource_unknown (res_a, lyr_a, input, error);
}
if (error && *error)
return -1;

View File

@ -131,6 +131,7 @@ static const Babl* get_layer_format (PSDimage *img_a,
static const Babl* get_channel_format (PSDimage *img_a);
static const Babl* get_mask_format (PSDimage *img_a);
static void initialize_unsupported (PSDSupport *supported_features);
/* Main file load function */
GimpImage *
@ -138,6 +139,7 @@ load_image (GFile *file,
gboolean merged_image_only,
gboolean *resolution_loaded,
gboolean *profile_loaded,
PSDSupport *unsupported_features,
GError **load_error)
{
GInputStream *input;
@ -149,6 +151,9 @@ load_image (GFile *file,
img_a.cmyk_transform = img_a.cmyk_transform_alpha = NULL;
img_a.cmyk_profile = NULL;
initialize_unsupported (unsupported_features);
img_a.unsupported_features = unsupported_features;
/* ----- Open PSD file ----- */
input = G_INPUT_STREAM (g_file_read (file, NULL, &error));
@ -1030,6 +1035,8 @@ read_layer_info (PSDimage *img_a,
return NULL;
}
lyr_a[lidx]->unsupported_features = img_a->unsupported_features;
if (load_layer_resource (&res_a, lyr_a[lidx], input, error) < 0)
{
free_lyr_a (lyr_a, img_a->num_layers);
@ -1620,6 +1627,8 @@ add_layers (GimpImage *image,
gidx = -1;
for (lidx = 0; lidx < img_a->num_layers; ++lidx)
{
lyr_a[lidx]->unsupported_features = img_a->unsupported_features;
if (lyr_a[lidx]->clipping == 1)
{
/* Photoshop handles layers with clipping differently than GIMP does.
@ -3269,44 +3278,145 @@ get_mask_format (PSDimage *img_a)
return format;
}
static void
initialize_unsupported (PSDSupport *unsupported_features)
{
unsupported_features->show_gui = FALSE;
unsupported_features->duotone_mode = FALSE;
unsupported_features->adjustment_layer = FALSE;
unsupported_features->fill_layer = FALSE;
unsupported_features->text_layer = FALSE;
unsupported_features->linked_layer = FALSE;
unsupported_features->vector_mask = FALSE;
unsupported_features->smart_object = FALSE;
unsupported_features->stroke = FALSE;
unsupported_features->layer_effect = FALSE;
unsupported_features->layer_comp = FALSE;
}
void
load_dialog (void)
load_dialog (PSDSupport *unsupported_features)
{
GtkWidget *dialog;
GtkWidget *label;
GtkWidget *vbox;
gchar *label_text;
dialog = gimp_dialog_new (_("PSD Compatibility Notice"),
"psd-compatibility-notice",
dialog = gimp_dialog_new (_("Import PSD"),
"import-psd",
NULL, 0, NULL, NULL,
_("_OK"), GTK_RESPONSE_OK,
NULL);
gimp_window_set_transient (GTK_WINDOW (dialog));
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
vbox, TRUE, TRUE, 0);
gtk_widget_show (vbox);
/* Duotone import notification */
label_text = g_strdup_printf ("<b>%s</b>\n%s", _("Duotone Import"),
_("Image will be imported as Grayscale.\n"
"Duotone color space data has been saved\n"
"and can be reapplied on export."));
label = gtk_label_new (NULL);
gtk_label_set_markup (GTK_LABEL (label), label_text);
if (unsupported_features->duotone_mode)
{
gchar *label_text;
gtk_label_set_selectable (GTK_LABEL (label), TRUE);
gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
gtk_label_set_yalign (GTK_LABEL (label), 0.0);
gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0);
gtk_widget_show (label);
label_text = g_strdup_printf ("<b>%s</b>\n%s", _("Duotone Import"),
_("Image will be imported as Grayscale.\n"
"Duotone color space data has been saved\n"
"and can be reapplied on export."));
label = gtk_label_new (NULL);
gtk_label_set_markup (GTK_LABEL (label), label_text);
g_free (label_text);
gtk_label_set_selectable (GTK_LABEL (label), TRUE);
gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
gtk_label_set_yalign (GTK_LABEL (label), 0.0);
gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0);
gtk_widget_show (label);
g_free (label_text);
}
if (unsupported_features->show_gui)
{
GtkWidget *scrolled_window;
GtkWidget *title_label;
gchar *message = "";
gchar *title = g_strdup_printf ("<b>%s</b>\n%s\n",
_("Compatibility Notice"),
_("This PSD file contains features "
"that\n are not yet fully supported "
"in GIMP:"));
title_label = gtk_label_new (NULL);
gtk_label_set_markup (GTK_LABEL (title_label), title);
gtk_label_set_justify (GTK_LABEL (title_label), GTK_JUSTIFY_LEFT);
gtk_label_set_line_wrap (GTK_LABEL (title_label), TRUE);
gtk_label_set_yalign (GTK_LABEL (title_label), 0.0);
gtk_box_pack_start (GTK_BOX (vbox), title_label, FALSE, FALSE, 0);
gtk_widget_show (title_label);
if (unsupported_features->adjustment_layer)
message = g_strdup_printf ("%s\n\xE2\x80\xA2 %s", message,
_("Adjustment layers are not yet "
"supported and will be dropped."));
if (unsupported_features->fill_layer)
message = g_strdup_printf ("%s\n\xE2\x80\xA2 %s", message,
_("Fill layers are partially "
"supported and will be converted "
"to raster layers."));
if (unsupported_features->text_layer)
message = g_strdup_printf ("%s\n\xE2\x80\xA2 %s", message,
_("Text layers are partially "
"supported and will be converted "
"to raster layers."));
if (unsupported_features->linked_layer)
message = g_strdup_printf ("%s\n\xE2\x80\xA2 %s", message,
_("Linked layers are are not yet "
"supported and will be dropped."));
if (unsupported_features->vector_mask)
message = g_strdup_printf ("%s\n\xE2\x80\xA2 %s", message,
_("Vector masks are partially "
"supported and will be converted "
"to raster layers."));
if (unsupported_features->stroke)
message = g_strdup_printf ("%s\n\xE2\x80\xA2 %s", message,
_("Vector strokes are not yet "
"supported and will be dropped."));
if (unsupported_features->layer_effect)
message = g_strdup_printf ("%s\n\xE2\x80\xA2 %s", message,
_("Layer effects are not yet "
"supported and will be dropped."));
if (unsupported_features->smart_object)
message = g_strdup_printf ("%s\n\xE2\x80\xA2 %s", message,
_("Smart objects are not yet "
"supported and will be dropped."));
if (unsupported_features->layer_comp)
message = g_strdup_printf ("%s\n\xE2\x80\xA2 %s", message,
_("Layer comps are not yet "
"supported and will be dropped."));
scrolled_window = gtk_scrolled_window_new (NULL, NULL);
gtk_widget_set_size_request (scrolled_window, -1, 100);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window), GTK_SHADOW_OUT);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
GTK_POLICY_NEVER,
GTK_POLICY_AUTOMATIC);
gtk_box_pack_start (GTK_BOX (vbox), scrolled_window, TRUE, TRUE, 0);
gtk_widget_show (scrolled_window);
label = gtk_label_new (NULL);
gtk_label_set_markup (GTK_LABEL (label), message);
gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
gtk_label_set_yalign (GTK_LABEL (label), 0.0);
gtk_container_add (GTK_CONTAINER (scrolled_window), label);
gtk_widget_show (label);
g_free (title);
g_free (message);
}
gtk_widget_show (dialog);

View File

@ -26,9 +26,10 @@ GimpImage * load_image (GFile *file,
gboolean merged_image_only,
gboolean *resolution_loaded,
gboolean *profile_loaded,
PSDSupport *unsupported_features,
GError **error);
void load_dialog (void);
void load_dialog (PSDSupport *unsupported_features);
#endif /* __PSD_LOAD_H__ */

View File

@ -276,6 +276,7 @@ psd_load (GimpProcedure *procedure,
GimpMetadata *metadata;
GimpParasite *parasite = NULL;
GError *error = NULL;
PSDSupport unsupported_features;
gegl_init (NULL, NULL);
@ -294,6 +295,7 @@ psd_load (GimpProcedure *procedure,
LOAD_MERGED_PROC) == 0,
&resolution_loaded,
&profile_loaded,
&unsupported_features,
&error);
if (! image)
@ -306,10 +308,14 @@ psd_load (GimpProcedure *procedure,
{
parasite = gimp_image_get_parasite (image, PSD_PARASITE_DUOTONE_DATA);
if (parasite)
{
load_dialog ();
gimp_parasite_free (parasite);
}
unsupported_features.duotone_mode = TRUE;
if (unsupported_features.duotone_mode ||
unsupported_features.show_gui)
load_dialog (&unsupported_features);
if (parasite)
gimp_parasite_free (parasite);
}
metadata = gimp_image_metadata_load_prepare (image, "image/x-psd",

View File

@ -137,13 +137,15 @@
#define PSD_LFX_BEVEL "bevl" /* Effects layer - bevel (PS5) */
/* Placed Layer */
#define PSD_LPL_PLACE_LAYER "plLd" /* Placed layer (?) */
#define PSD_LPL_PLACE_LAYER "PlLd" /* Placed layer (?) (based on PSD files, not specification) */
#define PSD_LPL_PLACE_LAYER_NEW "SoLd" /* Placed layer (PS10) */
#define PSD_SMART_OBJECT_LAYER "SoLE" /* Smart Object Layer (CC2015) */
/* Linked Layer */
#define PSD_LLL_LINKED_LAYER "lnkD" /* Linked layer (?) */
#define PSD_LLL_LINKED_LAYER_2 "lnk2" /* Linked layer 2nd key */
#define PSD_LLL_LINKED_LAYER_3 "lnk3" /* Linked layer 3rd key */
#define PSD_LLL_LINKED_LAYER "lnkD" /* Linked layer (?) */
#define PSD_LLL_LINKED_LAYER_2 "lnk2" /* Linked layer 2nd key */
#define PSD_LLL_LINKED_LAYER_3 "lnk3" /* Linked layer 3rd key */
#define PSD_LLL_LINKED_LAYER_EXT "lnkE" /* Linked layer external */
/* Merged Transparency */
#define PSD_LMT_MERGE_TRANS "Mtrn" /* Merged transparency save flag (?) */
@ -577,6 +579,23 @@ typedef struct
gchar *info; /* Text information */
} PSDText;
/* Partially or Unsupported Features */
typedef struct
{
gboolean show_gui;
gboolean duotone_mode;
gboolean adjustment_layer;
gboolean fill_layer;
gboolean text_layer;
gboolean linked_layer;
gboolean vector_mask;
gboolean smart_object;
gboolean stroke;
gboolean layer_effect;
gboolean layer_comp;
} PSDSupport;
/* PSD Layer data structure */
typedef struct
{
@ -604,6 +623,8 @@ typedef struct
guint32 id; /* Layer ID (Tattoo) */
guchar group_type; /* 0 -> not a group; 1 -> open folder; 2 -> closed folder; 3 -> end of group */
guint16 color_tag[4]; /* 4 * 16 bit color components */
PSDSupport *unsupported_features;
} PSDlayer;
/* PSD Channel data structure */
@ -685,6 +706,8 @@ typedef struct
GimpColorProfile *cmyk_profile;
gpointer cmyk_transform;
gpointer cmyk_transform_alpha;
PSDSupport *unsupported_features;
} PSDimage;
/* Public functions */