summaryrefslogtreecommitdiff
path: root/source/fitz/output-psd.c
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2017-07-12 21:18:45 +0100
committerRobin Watts <robin.watts@artifex.com>2017-07-19 19:41:23 +0100
commitd54763bcd644364c19d3a6a12f889127df583e01 (patch)
tree379843a30fbb263e811ac6cbe3d2a4abe13b6fb3 /source/fitz/output-psd.c
parentd541fc4b9eced1b788377df8c7edfd9b8dea4094 (diff)
downloadmupdf-d54763bcd644364c19d3a6a12f889127df583e01.tar.xz
Update band writer (especially PSD) to cope with spots
PSD writer now outputs spot colors. Ensure subtractive colorspaces are stored with proper polarity. The CMYK and spot components need to be 255-X in the PSD format Store PSD format resources using correct Pascal style strings. Photoshop will fail to open if the the ICC profile resource name is not in proper format. (Incorporates fixes from Michael).
Diffstat (limited to 'source/fitz/output-psd.c')
-rw-r--r--source/fitz/output-psd.c130
1 files changed, 119 insertions, 11 deletions
diff --git a/source/fitz/output-psd.c b/source/fitz/output-psd.c
index 1c7adbc5..4d0f9574 100644
--- a/source/fitz/output-psd.c
+++ b/source/fitz/output-psd.c
@@ -11,7 +11,7 @@ fz_save_pixmap_as_psd(fz_context *ctx, fz_pixmap *pixmap, const char *filename)
fz_try(ctx)
{
writer = fz_new_psd_band_writer(ctx, out);
- fz_write_header(ctx, writer, pixmap->w, pixmap->h, pixmap->n, pixmap->alpha, pixmap->xres, pixmap->yres, 0, pixmap->colorspace);
+ fz_write_header(ctx, writer, pixmap->w, pixmap->h, pixmap->n, pixmap->alpha, pixmap->xres, pixmap->yres, 0, pixmap->colorspace, pixmap->seps);
fz_write_band(ctx, writer, pixmap->stride, pixmap->h, pixmap->samples);
}
fz_always(ctx)
@@ -37,7 +37,7 @@ fz_write_pixmap_as_psd(fz_context *ctx, fz_output *out, const fz_pixmap *pixmap)
fz_try(ctx)
{
- fz_write_header(ctx, writer, pixmap->w, pixmap->h, pixmap->n, pixmap->alpha, pixmap->xres, pixmap->yres, 0, pixmap->colorspace);
+ fz_write_header(ctx, writer, pixmap->w, pixmap->h, pixmap->n, pixmap->alpha, pixmap->xres, pixmap->yres, 0, pixmap->colorspace, pixmap->seps);
fz_write_band(ctx, writer, pixmap->stride, pixmap->h, pixmap->samples);
}
fz_always(ctx)
@@ -53,6 +53,7 @@ fz_write_pixmap_as_psd(fz_context *ctx, fz_output *out, const fz_pixmap *pixmap)
typedef struct psd_band_writer_s
{
fz_band_writer super;
+ int num_additive;
} psd_band_writer;
static void
@@ -62,21 +63,29 @@ psd_write_header(fz_context *ctx, fz_band_writer *writer_, const fz_colorspace *
fz_output *out = writer->super.out;
int w = writer->super.w;
int h = writer->super.h;
+ int s = writer->super.s;
int n = writer->super.n;
- int alpha = writer->super.alpha;
+ int c = n - writer->super.alpha - s;
+ fz_separations *seps = writer->super.seps;
+ int i;
+ size_t len;
static const char psdsig[12] = { '8', 'B', 'P', 'S', 0, 1, 0, 0, 0, 0, 0, 0 };
static const char ressig[4] = { '8', 'B', 'I', 'M' };
fz_buffer *buffer = fz_icc_data_from_icc_colorspace(ctx, cs);
unsigned char *data;
size_t size = fz_buffer_storage(ctx, buffer, &data);
+ if (!fz_colorspace_is_subtractive(ctx, cs))
+ writer->num_additive = fz_colorspace_n(ctx, cs);
+
/* File Header Section */
fz_write_data(ctx, out, psdsig, 12);
fz_write_int16_be(ctx, out, n);
fz_write_int32_be(ctx, out, h);
fz_write_int32_be(ctx, out, w);
fz_write_int16_be(ctx, out, 8); /* bits per channel */
- switch (n - alpha)
+
+ switch (c)
{
case 0:
case 1:
@@ -96,22 +105,105 @@ psd_write_header(fz_context *ctx, fz_band_writer *writer_, const fz_colorspace *
/* Color Mode Data Section - empty */
fz_write_int32_be(ctx, out, 0);
- /* Image Resources Section */
- if (size == 0)
- fz_write_int32_be(ctx, out, 0);
- else
+ /* Image Resources Section - Spot Names, Equivalent colors, resolution, ICC Profile */
+ /* Spot names */
+ len = 0;
+ for (i = 0; i < s; i++)
+ {
+ const char *name = fz_get_separation(ctx, seps, i, NULL, NULL);
+ char text[32];
+ size_t len2;
+ if (name == NULL)
+ {
+ sprintf(text, "Spot%d", i-4);
+ name = text;
+ }
+ len2 = strlen(name);
+ if (len2 > 255)
+ len2 = 255;
+ len += len2 + 1;
+ }
+
+ /* Write the size of all the following resources */
+ fz_write_int32_be(ctx, out,
+ (s ? 12 + ((len + 1)&~1) : 0) + /* Spot Names */
+ (s ? 12 + (14 * s) : 0) + /* DisplayInfo */
+ 28 + /* Resolutions */
+ (size ? (size+19)&~1 : 0)); /* ICC Profile */
+
+ /* Spot names */
+ if (s != 0)
+ {
+ fz_write_data(ctx, out, ressig, 4);
+ fz_write_int16_be(ctx, out , 0x03EE);
+ fz_write_int16_be(ctx, out, 0); /* PString */
+ fz_write_int32_be(ctx, out, (len + 1)&~1);
+ for (i = 0; i < s; i++) {
+ size_t len2;
+ const char *name = fz_get_separation(ctx, seps, i, NULL, NULL);
+ char text[32];
+ if (name == NULL)
+ {
+ sprintf(text, "Spot%d", i-4);
+ name = text;
+ }
+ len2 = strlen(name);
+ if (len2 > 255)
+ len2 = 255;
+ fz_write_byte(ctx, out, len2);
+ fz_write_data(ctx, out, name, len2);
+ }
+ if (len & 1)
+ {
+ fz_write_byte(ctx, out, 0);
+ }
+
+ /* DisplayInfo - Colors for each spot channel */
+ fz_write_data(ctx, out, ressig, 4);
+ fz_write_int16_be(ctx, out, 0x03EF);
+ fz_write_int16_be(ctx, out, 0); /* PString */
+ fz_write_int32_be(ctx, out, 14 * s); /* Length */
+ for (i = 0; i < s; i++) {
+ uint32_t cmyk;
+ (void)fz_get_separation(ctx, seps, i, NULL, &cmyk);
+ fz_write_int16_be(ctx, out, 02); /* CMYK */
+ /* PhotoShop stores all component values as if they were additive. */
+ fz_write_int16_be(ctx, out, 257 * (cmyk & 0xFF));/* Cyan */
+ fz_write_int16_be(ctx, out, 257 * ((cmyk>>8) & 0xFF));/* Magenta */
+ fz_write_int16_be(ctx, out, 257 * ((cmyk>>16) & 0xFF));/* Yellow */
+ fz_write_int16_be(ctx, out, 257 * ((cmyk>>24) & 0xFF));/* Black */
+ fz_write_int16_be(ctx, out, 0); /* Opacity 0 to 100 */
+ fz_write_byte(ctx, out, 2); /* Don't know */
+ fz_write_byte(ctx, out, 0); /* Padding - Always Zero */
+ }
+ }
+
+ /* ICC Profile - (size + 19)&~1 bytes */
+ if (size != 0)
{
- /* ICC Profile */
- fz_write_int32_be(ctx, out, 4+2+8+size+(size&1));
/* Image Resource block */
fz_write_data(ctx, out, ressig, 4);
fz_write_int16_be(ctx, out, 0x40f); /* ICC Profile */
- fz_write_data(ctx, out, "\0Profile", 8); /* Profile name (must be even!) */
+ fz_write_data(ctx, out, "\x07Profile", 8); /* Profile name (must be even!) */
+ fz_write_int32_be(ctx, out, size);
fz_write_data(ctx, out, data, size); /* Actual data */
if (size & 1)
fz_write_byte(ctx, out, 0); /* Pad to even */
}
+ /* Image resolution - 28 bytes */
+ fz_write_data(ctx, out, ressig, 4);
+ fz_write_int16_be(ctx, out, 0x03ED);
+ fz_write_int16_be(ctx, out, 0); /* PString */
+ fz_write_int32_be(ctx, out, 16); /* Length */
+ /* Resolution is specified as a fixed 16.16 bits */
+ fz_write_int32_be(ctx, out, writer->super.xres);
+ fz_write_int16_be(ctx, out, 1); /* width: 1 --> resolution is pixels per inch */
+ fz_write_int16_be(ctx, out, 1); /* width: 1 --> resolution is pixels per inch */
+ fz_write_int32_be(ctx, out, writer->super.yres);
+ fz_write_int16_be(ctx, out, 1); /* height: 1 --> resolution is pixels per inch */
+ fz_write_int16_be(ctx, out, 1); /* height: 1 --> resolution is pixels per inch */
+
/* Layer and Mask Information Section */
fz_write_int32_be(ctx, out, 0);
@@ -120,6 +212,15 @@ psd_write_header(fz_context *ctx, fz_band_writer *writer_, const fz_colorspace *
}
static void
+psd_invert_buffer(unsigned char *buffer, int size)
+{
+ int k;
+
+ for (k = 0; k < size; k++)
+ buffer[k] = 255 - buffer[k];
+}
+
+static void
psd_write_band(fz_context *ctx, fz_band_writer *writer_, int stride, int band_start, int band_height, const unsigned char *sp)
{
psd_band_writer *writer = (psd_band_writer *)(void *)writer_;
@@ -131,6 +232,7 @@ psd_write_band(fz_context *ctx, fz_band_writer *writer_, int stride, int band_st
unsigned char *b;
int plane_inc;
int line_skip;
+ int num_additive = writer->num_additive;
if (!out)
return;
@@ -156,6 +258,8 @@ psd_write_band(fz_context *ctx, fz_band_writer *writer_, int stride, int band_st
sp += n;
if (b == buffer_end)
{
+ if (k >= num_additive)
+ psd_invert_buffer(buffer, sizeof(buffer));
fz_write_data(ctx, out, buffer, sizeof(buffer));
b = buffer;
}
@@ -165,6 +269,8 @@ psd_write_band(fz_context *ctx, fz_band_writer *writer_, int stride, int band_st
sp -= stride * band_height - 1;
if (b != buffer)
{
+ if (k >= num_additive)
+ psd_invert_buffer(buffer, sizeof(buffer));
fz_write_data(ctx, out, buffer, b - buffer);
b = buffer;
}
@@ -200,5 +306,7 @@ fz_band_writer *fz_new_psd_band_writer(fz_context *ctx, fz_output *out)
writer->super.trailer = psd_write_trailer;
writer->super.drop = psd_drop_band_writer;
+ writer->num_additive = 0;
+
return &writer->super;
}