From d54763bcd644364c19d3a6a12f889127df583e01 Mon Sep 17 00:00:00 2001 From: Robin Watts Date: Wed, 12 Jul 2017 21:18:45 +0100 Subject: 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). --- source/fitz/output-psd.c | 130 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 119 insertions(+), 11 deletions(-) (limited to 'source/fitz/output-psd.c') 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); @@ -119,6 +211,15 @@ psd_write_header(fz_context *ctx, fz_band_writer *writer_, const fz_colorspace * fz_write_int16_be(ctx, out, 0); /* Raw image data */ } +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) { @@ -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; } -- cgit v1.2.3