From a3fb3ca11032515e64eeddba64cdaab5eaadbbff Mon Sep 17 00:00:00 2001 From: Alx Sa Date: Sun, 24 Jul 2022 16:36:35 +0000 Subject: [PATCH] plug-ins: Enable export of original Duotone data Optionally includes the previously saved Duotone color space data on PSD export. New load dialogue alerts user if duotone data was imported. New export dialogue appears if the image is still grayscale and the parasite exists. If selected, the mode is set to PSD_DUOTONE in the header and the original duotone data is written in the color space section. --- plug-ins/file-psd/psd-load.c | 48 ++++++++++++++ plug-ins/file-psd/psd-load.h | 12 ++-- plug-ins/file-psd/psd-save.c | 125 ++++++++++++++++++++++++++++++----- plug-ins/file-psd/psd-save.h | 10 ++- plug-ins/file-psd/psd.c | 48 ++++++++++++-- 5 files changed, 215 insertions(+), 28 deletions(-) diff --git a/plug-ins/file-psd/psd-load.c b/plug-ins/file-psd/psd-load.c index 5a3c69de8e..7dfa256b9f 100644 --- a/plug-ins/file-psd/psd-load.c +++ b/plug-ins/file-psd/psd-load.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "psd.h" #include "psd-util.h" @@ -3268,3 +3269,50 @@ get_mask_format (PSDimage *img_a) return format; } + +void +load_dialog (void) +{ + GtkWidget *dialog; + GtkWidget *label; + GtkWidget *vbox; + gchar *label_text; + + dialog = gimp_dialog_new (_("PSD Compatibility Notice"), + "psd-compatibility-notice", + NULL, 0, NULL, NULL, + _("_OK"), GTK_RESPONSE_OK, + NULL); + + gimp_window_set_transient (GTK_WINDOW (dialog)); + + vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12); + 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 ("%s\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); + + 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); + + gtk_widget_show (dialog); + + /* run the dialog */ + gimp_dialog_run (GIMP_DIALOG (dialog)); + + gtk_widget_destroy (dialog); +} diff --git a/plug-ins/file-psd/psd-load.h b/plug-ins/file-psd/psd-load.h index 565f9ef750..cd49d95cfd 100644 --- a/plug-ins/file-psd/psd-load.h +++ b/plug-ins/file-psd/psd-load.h @@ -22,11 +22,13 @@ #define __PSD_LOAD_H__ -GimpImage * load_image (GFile *file, - gboolean merged_image_only, - gboolean *resolution_loaded, - gboolean *profile_loaded, - GError **error); +GimpImage * load_image (GFile *file, + gboolean merged_image_only, + gboolean *resolution_loaded, + gboolean *profile_loaded, + GError **error); + +void load_dialog (void); #endif /* __PSD_LOAD_H__ */ diff --git a/plug-ins/file-psd/psd-save.c b/plug-ins/file-psd/psd-save.c index 4419e75c1c..5767384512 100644 --- a/plug-ins/file-psd/psd-save.c +++ b/plug-ins/file-psd/psd-save.c @@ -132,13 +132,16 @@ static const gchar * psd_lmode_layer (GimpLayer *layer, static void reshuffle_cmap_write (guchar *mapGimp); static void save_header (GOutputStream *output, - GimpImage *image); + GimpImage *image, + gboolean export_duotone); static void save_color_mode_data (GOutputStream *output, - GimpImage *image); + GimpImage *image, + gboolean export_duotone); static void save_resources (GOutputStream *output, - GimpImage *image); + GimpImage *image, + gboolean export_duotone); static void save_layer_and_mask (GOutputStream *output, GimpImage *image); @@ -524,7 +527,8 @@ reshuffle_cmap_write (guchar *mapGimp) static void save_header (GOutputStream *output, - GimpImage *image) + GimpImage *image, + gboolean export_duotone) { IFDBG(1) g_debug ("Function: save_header\n" "\tRows: %d\n" @@ -545,20 +549,42 @@ save_header (GOutputStream *output, write_gint32 (output, PSDImageData.image_height, "rows"); write_gint32 (output, PSDImageData.image_width, "columns"); write_gint16 (output, 8 * get_bpc (image), "depth"); - write_gint16 (output, gimpBaseTypeToPsdMode (PSDImageData.baseType), "mode"); + if (export_duotone) + write_gint16 (output, PSD_DUOTONE, "mode"); + else + write_gint16 (output, gimpBaseTypeToPsdMode (PSDImageData.baseType), "mode"); } static void save_color_mode_data (GOutputStream *output, - GimpImage *image) + GimpImage *image, + gboolean export_duotone) { - guchar *cmap; - guchar *cmap_modified; - gint i; - gint32 nColors; + guchar *cmap; + guchar *cmap_modified; + gint i; + gint32 nColors; + GimpParasite *parasite = NULL; IFDBG(1) g_debug ("Function: save_color_mode_data"); + parasite = gimp_image_get_parasite (image, PSD_PARASITE_DUOTONE_DATA); + if (export_duotone && parasite) + { + const guchar *parasite_data; + guint32 parasite_size; + + IFDBG(1) g_debug ("\tImage type: DUOTONE"); + + parasite_data = (const guchar *) gimp_parasite_get_data (parasite, ¶site_size); + + write_gint32 (output, parasite_size, "color data length"); + xfwrite (output, parasite_data, parasite_size, "colormap"); + + gimp_parasite_free (parasite); + return; + } + switch (PSDImageData.baseType) { case GIMP_INDEXED: @@ -607,7 +633,8 @@ save_color_mode_data (GOutputStream *output, static void save_resources (GOutputStream *output, - GimpImage *image) + GimpImage *image, + gboolean export_duotone) { GList *iter; gint i; @@ -885,9 +912,10 @@ save_resources (GOutputStream *output, /* --------------- Write ICC profile data ------------------- */ { - GimpColorProfile *profile; + GimpColorProfile *profile = NULL; - profile = gimp_image_get_effective_color_profile (image); + if (! export_duotone) + profile = gimp_image_get_effective_color_profile (image); if (profile) { @@ -1754,12 +1782,19 @@ clear_image_data (void) gboolean save_image (GFile *file, GimpImage *image, + GObject *config, GError **error) { GOutputStream *output; GeglBuffer *buffer; GList *iter; GError *local_error = NULL; + GimpParasite *parasite = NULL; + gboolean config_duotone; + + g_object_get (config, + "duotone", &config_duotone, + NULL); IFDBG(1) g_debug ("Function: save_image"); @@ -1777,6 +1812,22 @@ save_image (GFile *file, gimp_progress_init_printf (_("Exporting '%s'"), gimp_file_get_utf8_name (file)); + /* If image is not grayscale or lacks Duotone color space parasite, + * turn off "Export as Duotone". + */ + parasite = gimp_image_get_parasite (image, PSD_PARASITE_DUOTONE_DATA); + if (parasite) + { + if (gimp_image_get_base_type (image) != GIMP_GRAY) + config_duotone = FALSE; + + gimp_parasite_free (parasite); + } + else + { + config_duotone = FALSE; + } + get_image_data (image); /* Need to check each of the layers size individually also */ @@ -1828,9 +1879,9 @@ save_image (GFile *file, IFDBG(1) g_debug ("\tFile '%s' has been opened", gimp_file_get_utf8_name (file)); - save_header (output, image); - save_color_mode_data (output, image); - save_resources (output, image); + save_header (output, image, config_duotone); + save_color_mode_data (output, image, config_duotone); + save_resources (output, image, config_duotone); /* PSD format does not support layers in indexed images */ @@ -2025,3 +2076,45 @@ image_get_all_layers (GimpImage *image, return psd_layers; } + +gboolean +save_dialog (GimpImage *image, + GimpProcedure *procedure, + GObject *config) +{ + GtkWidget *dialog; + GtkWidget *duotone_notice; + gboolean run; + + dialog = gimp_procedure_dialog_new (procedure, + GIMP_PROCEDURE_CONFIG (config), + _("Export Image as PSD")); + + /* Profile label */ + duotone_notice = gimp_procedure_dialog_get_label (GIMP_PROCEDURE_DIALOG (dialog), + "duotone-notice", + _("Duotone color space information " + "from the original\nimported image " + "will be used.")); + gtk_label_set_xalign (GTK_LABEL (duotone_notice), 0.0); + gtk_label_set_ellipsize (GTK_LABEL (duotone_notice), PANGO_ELLIPSIZE_END); + gimp_label_set_attributes (GTK_LABEL (duotone_notice), + PANGO_ATTR_STYLE, PANGO_STYLE_ITALIC, + -1); + + gimp_procedure_dialog_fill_frame (GIMP_PROCEDURE_DIALOG (dialog), + "duotone-frame", "duotone", FALSE, + "duotone-notice"); + + gimp_procedure_dialog_fill (GIMP_PROCEDURE_DIALOG (dialog), + "duotone-frame", + NULL); + + gtk_widget_show (dialog); + + run = gimp_procedure_dialog_run (GIMP_PROCEDURE_DIALOG (dialog)); + + gtk_widget_destroy (dialog); + + return run; +} diff --git a/plug-ins/file-psd/psd-save.h b/plug-ins/file-psd/psd-save.h index a55792ea8b..26d735df74 100644 --- a/plug-ins/file-psd/psd-save.h +++ b/plug-ins/file-psd/psd-save.h @@ -19,9 +19,13 @@ #define __PSD_SAVE_H__ -gboolean save_image (GFile *file, - GimpImage *image, - GError **error); +gboolean save_image (GFile *file, + GimpImage *image, + GObject *config, + GError **error); +gboolean save_dialog (GimpImage *image, + GimpProcedure *procedure, + GObject *config); #endif /* __PSD_SAVE_H__ */ diff --git a/plug-ins/file-psd/psd.c b/plug-ins/file-psd/psd.c index 4e5b60e2f6..14e63872ac 100644 --- a/plug-ins/file-psd/psd.c +++ b/plug-ins/file-psd/psd.c @@ -223,6 +223,13 @@ psd_create_procedure (GimpPlugIn *plug_in, "image/x-psd"); gimp_file_procedure_set_extensions (GIMP_FILE_PROCEDURE (procedure), "psd"); + + GIMP_PROC_ARG_BOOLEAN (procedure, "duotone", + "Export as _Duotone", + "Export as a Duotone PSD file if Duotone color space information " + "was attached to the image when originally imported.", + FALSE, + G_PARAM_READWRITE); } return procedure; @@ -240,6 +247,7 @@ psd_load (GimpProcedure *procedure, gboolean profile_loaded = FALSE; GimpImage *image; GimpMetadata *metadata; + GimpParasite *parasite = NULL; GError *error = NULL; gegl_init (NULL, NULL); @@ -266,6 +274,17 @@ psd_load (GimpProcedure *procedure, GIMP_PDB_EXECUTION_ERROR, error); + /* If image was Duotone, notify user of compatibility */ + if (run_mode == GIMP_RUN_INTERACTIVE) + { + parasite = gimp_image_get_parasite (image, PSD_PARASITE_DUOTONE_DATA); + if (parasite) + { + load_dialog (); + gimp_parasite_free (parasite); + } + } + metadata = gimp_image_metadata_load_prepare (image, "image/x-psd", file, NULL); if (metadata) @@ -338,14 +357,21 @@ psd_save (GimpProcedure *procedure, const GimpValueArray *args, gpointer run_data) { + GimpProcedureConfig *config; GimpPDBStatusType status = GIMP_PDB_SUCCESS; GimpMetadata *metadata; GimpMetadataSaveFlags metadata_flags; GimpExportReturn export = GIMP_EXPORT_IGNORE; + GimpParasite *parasite = NULL; GError *error = NULL; gegl_init (NULL, NULL); + config = gimp_procedure_create_config (procedure); + metadata = gimp_image_metadata_save_prepare (image, + "image/x-psd", + &metadata_flags); + switch (run_mode) { case GIMP_RUN_INTERACTIVE: @@ -369,11 +395,25 @@ psd_save (GimpProcedure *procedure, break; } - metadata = gimp_image_metadata_save_prepare (image, - "image/x-psd", - &metadata_flags); + if (run_mode == GIMP_RUN_INTERACTIVE) + { + /* Only show dialog if image is grayscale and duotone color space + * information was attached from the original image imported + */ + parasite = gimp_image_get_parasite (image, PSD_PARASITE_DUOTONE_DATA); + if (parasite) + { + if (gimp_image_get_base_type (image) == GIMP_GRAY) + { + if (! save_dialog (image, procedure, G_OBJECT (config))) + return gimp_procedure_new_return_values (procedure, GIMP_PDB_CANCEL, + NULL); + } + gimp_parasite_free (parasite); + } + } - if (save_image (file, image, &error)) + if (save_image (file, image, G_OBJECT (config), &error)) { if (metadata) {