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.
This commit is contained in:
Alx Sa 2022-07-24 16:36:35 +00:00 committed by Jacob Boerema
parent 6b3d69a3c5
commit a3fb3ca110
5 changed files with 215 additions and 28 deletions

View File

@ -26,6 +26,7 @@
#include <glib/gstdio.h>
#include <zlib.h>
#include <libgimp/gimp.h>
#include <libgimp/gimpui.h>
#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 ("<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);
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);
}

View File

@ -28,5 +28,7 @@ GimpImage * load_image (GFile *file,
gboolean *profile_loaded,
GError **error);
void load_dialog (void);
#endif /* __PSD_LOAD_H__ */

View File

@ -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");
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;
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, &parasite_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,8 +912,9 @@ save_resources (GOutputStream *output,
/* --------------- Write ICC profile data ------------------- */
{
GimpColorProfile *profile;
GimpColorProfile *profile = NULL;
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;
}

View File

@ -21,7 +21,11 @@
gboolean save_image (GFile *file,
GimpImage *image,
GObject *config,
GError **error);
gboolean save_dialog (GimpImage *image,
GimpProcedure *procedure,
GObject *config);
#endif /* __PSD_SAVE_H__ */

View File

@ -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)
{