plug-ins: Convert CMYK u8 .psd to R'G'B' float on load

Patch from Massimo Valentini in issue #354, adapted for the new object
based plug-in APIs.
This commit is contained in:
Øyvind Kolås 2020-02-21 12:08:19 +01:00
parent 0f07f1baa5
commit 1462a91d86
3 changed files with 155 additions and 7 deletions

View File

@ -196,6 +196,7 @@ static gint load_resource_1033 (const PSDimageres *res_a,
GError **error);
static gint load_resource_1039 (const PSDimageres *res_a,
PSDimage *img_a,
GimpImage *image,
FILE *f,
GError **error);
@ -368,7 +369,7 @@ load_image_resource (PSDimageres *res_a,
break;
case PSD_ICC_PROFILE:
if (! load_resource_1039 (res_a, image, f, error))
if (! load_resource_1039 (res_a, img_a, image, f, error))
*profile_loaded = TRUE;
break;
@ -1105,6 +1106,7 @@ load_resource_1033 (const PSDimageres *res_a,
static gint
load_resource_1039 (const PSDimageres *res_a,
PSDimage *img_a,
GimpImage *image,
FILE *f,
GError **error)
@ -1128,8 +1130,16 @@ load_resource_1039 (const PSDimageres *res_a,
NULL);
if (profile)
{
gimp_image_set_color_profile (image, profile);
g_object_unref (profile);
if (img_a->color_mode == PSD_CMYK &&
gimp_color_profile_is_cmyk (profile))
{
img_a->cmyk_profile = profile;
}
else
{
gimp_image_set_color_profile (image, profile);
g_object_unref (profile);
}
}
g_free (icc_profile);

View File

@ -129,6 +129,8 @@ load_image (GFile *file,
filename = g_file_get_path (file);
img_a.cmyk_transform = img_a.cmyk_transform_alpha = NULL;
img_a.cmyk_profile = NULL;
/* ----- Open PSD file ----- */
if (g_stat (filename, &st) == -1)
{
@ -338,6 +340,7 @@ read_header_block (PSDimage *img_a,
&& img_a->color_mode != PSD_INDEXED
&& img_a->color_mode != PSD_RGB
&& img_a->color_mode != PSD_MULTICHANNEL
&& img_a->color_mode != PSD_CMYK
&& img_a->color_mode != PSD_DUOTONE)
{
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
@ -346,6 +349,17 @@ read_header_block (PSDimage *img_a,
return -1;
}
if (img_a->color_mode == PSD_CMYK)
{
if (img_a->bps != 8)
{
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
_("Unsupported color mode: %s"),
get_psd_color_mode_name (img_a->color_mode));
return -1;
}
}
/* Warning for unsupported bit depth */
switch (img_a->bps)
{
@ -1003,6 +1017,7 @@ create_gimp_image (PSDimage *img_a,
img_a->base_type = GIMP_INDEXED;
break;
case PSD_CMYK:
case PSD_RGB:
img_a->base_type = GIMP_RGB;
break;
@ -1026,7 +1041,10 @@ create_gimp_image (PSDimage *img_a,
case 8:
case 1:
precision = GIMP_PRECISION_U8_NON_LINEAR;
if (img_a->color_mode == PSD_CMYK)
precision = GIMP_PRECISION_FLOAT_NON_LINEAR;
else
precision = GIMP_PRECISION_U8_NON_LINEAR;
break;
default:
@ -1121,6 +1139,74 @@ add_image_resources (GimpImage *image,
return 0;
}
static guchar *
psd_convert_cmyk_to_srgb (PSDimage *img_a,
guchar *dst,
guchar *src,
gint width,
gint height,
gboolean alpha)
{
if (img_a->cmyk_profile)
{
if (alpha)
{
if (! img_a->cmyk_transform_alpha)
{
GimpColorProfile *srgb = gimp_color_profile_new_rgb_srgb ();
img_a->cmyk_transform_alpha = gimp_color_transform_new (img_a->cmyk_profile, babl_format ("cmykA u8"),
srgb, babl_format ("R'G'B'A float"),
0, 0);
g_object_unref (srgb);
}
gimp_color_transform_process_pixels (img_a->cmyk_transform_alpha,
babl_format ("cmykA u8"),
src,
babl_format ("R'G'B'A float"),
dst,
width * height);
}
else
{
if (! img_a->cmyk_transform)
{
GimpColorProfile *srgb = gimp_color_profile_new_rgb_srgb ();
img_a->cmyk_transform = gimp_color_transform_new (img_a->cmyk_profile, babl_format ("cmyk u8"),
srgb, babl_format ("R'G'B' float"),
0, 0);
g_object_unref (srgb);
}
gimp_color_transform_process_pixels (img_a->cmyk_transform_alpha,
babl_format ("cmyk u8"),
src,
babl_format ("R'G'B' float"),
dst,
width * height);
}
}
else
{
const Babl *fish;
if (alpha)
fish = babl_fish ("cmykA u8", "R'G'B'A float");
else
fish = babl_fish ("cmyk u8", "R'G'B' float");
babl_process (fish, src, dst, width * height);
}
return (guchar*) dst;
}
static gint
add_layers (GimpImage *image,
PSDimage *img_a,
@ -1554,6 +1640,48 @@ add_layers (GimpImage *image,
gint src_step = bps;
gint dst_step = bps * layer_channels;
if (img_a->color_mode == PSD_CMYK)
{
guchar *cmyk = g_new (guchar, layer_channels * iter->length);
for (cidx = 0; cidx < layer_channels; ++cidx)
{
gint b, y, x;
if (roi->x == 0 && roi->y == 0)
IFDBG(3) g_debug ("Start channel %d", channel_idx[cidx]);
for (b = 0; b < bps; ++b)
{
guint8 *dst = &cmyk[cidx * bps + b];
for (y = 0; y < roi->height; y++)
{
const guint8 *src;
src = (const guint8 *)
&lyr_chn[channel_idx[cidx]]->data[
((roi->y + y) * l_w +
roi->x) * bps +
b];
for (x = 0; x < roi->width; ++x)
{
*dst = *src;
src += src_step;
dst += dst_step;
}
}
}
}
psd_convert_cmyk_to_srgb (img_a, dst0, cmyk, roi->width, roi->height, alpha);
g_free (cmyk);
continue;
}
for (cidx = 0; cidx < layer_channels; ++cidx)
{
gint b;
@ -1873,11 +2001,14 @@ add_merged_image (GimpImage *image,
gimp_image_insert_layer (image, layer, NULL, 0);
buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (layer));
if (img_a->color_mode == PSD_CMYK)
img_a->color_mode = PSD_RGB;
gegl_buffer_set (buffer,
GEGL_RECTANGLE (0, 0,
gegl_buffer_get_width (buffer),
gegl_buffer_get_height (buffer)),
0, get_layer_format (img_a, img_a->transparency),
0, get_layer_format (img_a, (base_channels % 2) == 0),
pixels, GEGL_AUTO_ROWSTRIDE);
/* Merged image data is blended against white. Unblend it. */
@ -2344,6 +2475,7 @@ get_layer_format (PSDimage *img_a,
case 8:
case 1:
format = babl_format ("Y' u8");
break;
default:
@ -2387,7 +2519,8 @@ get_layer_format (PSDimage *img_a,
case 8:
case 1:
format = babl_format ("R'G'B' u8");
format = babl_format (img_a->color_mode == PSD_CMYK ? "R'G'B' float" : "R'G'B' u8");
break;
default:
@ -2409,7 +2542,8 @@ get_layer_format (PSDimage *img_a,
case 8:
case 1:
format = babl_format ("R'G'B'A u8");
format = babl_format (img_a->color_mode == PSD_CMYK ? "R'G'B'A float" : "R'G'B'A u8");
break;
default:

View File

@ -673,6 +673,10 @@ typedef struct
guint32 *alpha_id; /* Alpha channel ids (tattoos) */
guint16 alpha_id_count; /* Number of alpha channel id items */
guint16 quick_mask_id; /* Channel number containing quick mask */
GimpColorProfile *cmyk_profile;
gpointer cmyk_transform;
gpointer cmyk_transform_alpha;
} PSDimage;
/* Public functions */