diff options
author | Robin Watts <robin.watts@artifex.com> | 2017-06-15 19:08:10 +0100 |
---|---|---|
committer | Robin Watts <robin.watts@artifex.com> | 2017-06-22 14:59:48 +0100 |
commit | 5f0b9ee26becaf5153e8822cdc964b5d89050321 (patch) | |
tree | 7142ef56365ad9768d58e5402e66a2d3896e8a6c /source | |
parent | 2764ef8c0fd10d16a41842e8834efb1bd17e65d8 (diff) | |
download | mupdf-5f0b9ee26becaf5153e8822cdc964b5d89050321.tar.xz |
Add PSD device
Diffstat (limited to 'source')
-rw-r--r-- | source/fitz/output-psd.c | 204 | ||||
-rw-r--r-- | source/tools/mudraw.c | 12 |
2 files changed, 212 insertions, 4 deletions
diff --git a/source/fitz/output-psd.c b/source/fitz/output-psd.c new file mode 100644 index 00000000..1c7adbc5 --- /dev/null +++ b/source/fitz/output-psd.c @@ -0,0 +1,204 @@ +#include "mupdf/fitz.h" + +void +fz_save_pixmap_as_psd(fz_context *ctx, fz_pixmap *pixmap, const char *filename) +{ + fz_output *out = fz_new_output_with_path(ctx, filename, 0); + fz_band_writer *writer = NULL; + + fz_var(writer); + + 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_band(ctx, writer, pixmap->stride, pixmap->h, pixmap->samples); + } + fz_always(ctx) + { + fz_drop_band_writer(ctx, writer); + fz_drop_output(ctx, out); + } + fz_catch(ctx) + { + fz_rethrow(ctx); + } +} + +void +fz_write_pixmap_as_psd(fz_context *ctx, fz_output *out, const fz_pixmap *pixmap) +{ + fz_band_writer *writer; + + if (!out) + return; + + writer = fz_new_psd_band_writer(ctx, out); + + 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_band(ctx, writer, pixmap->stride, pixmap->h, pixmap->samples); + } + fz_always(ctx) + { + fz_drop_band_writer(ctx, writer); + } + fz_catch(ctx) + { + fz_rethrow(ctx); + } +} + +typedef struct psd_band_writer_s +{ + fz_band_writer super; +} psd_band_writer; + +static void +psd_write_header(fz_context *ctx, fz_band_writer *writer_, const fz_colorspace *cs) +{ + psd_band_writer *writer = (psd_band_writer *)(void *)writer_; + fz_output *out = writer->super.out; + int w = writer->super.w; + int h = writer->super.h; + int n = writer->super.n; + int alpha = writer->super.alpha; + 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); + + /* 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) + { + case 0: + case 1: + fz_write_int16_be(ctx, out, 1); /* Greyscale */ + break; + case 3: + fz_write_int16_be(ctx, out, 3); /* RGB */ + break; + case 4: + fz_write_int16_be(ctx, out, 4); /* CMYK */ + break; + default: + fz_write_int16_be(ctx, out, 7); /* Multichannel */ + break; + } + + /* 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 + { + /* 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, data, size); /* Actual data */ + if (size & 1) + fz_write_byte(ctx, out, 0); /* Pad to even */ + } + + /* Layer and Mask Information Section */ + fz_write_int32_be(ctx, out, 0); + + /* Image Data Section */ + fz_write_int16_be(ctx, out, 0); /* Raw image data */ +} + +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_; + fz_output *out = writer->super.out; + int y, x, k, finalband; + int w, h, n; + unsigned char buffer[256]; + unsigned char *buffer_end = &buffer[sizeof(buffer)]; + unsigned char *b; + int plane_inc; + int line_skip; + + if (!out) + return; + + w = writer->super.w; + h = writer->super.h; + n = writer->super.n; + + finalband = (band_start+band_height >= h); + if (finalband) + band_height = h - band_start; + + plane_inc = w * (h - band_height); + line_skip = stride - w*n; + b = buffer; + for (k = 0; k < n; k++) + { + for (y = 0; y < band_height; y++) + { + for (x = 0; x < w; x++) + { + *b++ = *sp; + sp += n; + if (b == buffer_end) + { + fz_write_data(ctx, out, buffer, sizeof(buffer)); + b = buffer; + } + } + sp += line_skip; + } + sp -= stride * band_height - 1; + if (b != buffer) + { + fz_write_data(ctx, out, buffer, b - buffer); + b = buffer; + } + fz_seek_output(ctx, out, plane_inc, FZ_SEEK_CUR); + } + fz_seek_output(ctx, out, w * h * (1-n), FZ_SEEK_CUR); +} + +static void +psd_write_trailer(fz_context *ctx, fz_band_writer *writer_) +{ + psd_band_writer *writer = (psd_band_writer *)(void *)writer_; + fz_output *out = writer->super.out; + + (void)out; + (void)writer; +} + +static void +psd_drop_band_writer(fz_context *ctx, fz_band_writer *writer_) +{ + psd_band_writer *writer = (psd_band_writer *)(void *)writer_; + + (void)writer; +} + +fz_band_writer *fz_new_psd_band_writer(fz_context *ctx, fz_output *out) +{ + psd_band_writer *writer = fz_new_band_writer(ctx, psd_band_writer, out); + + writer->super.header = psd_write_header; + writer->super.band = psd_write_band; + writer->super.trailer = psd_write_trailer; + writer->super.drop = psd_drop_band_writer; + + return &writer->super; +} diff --git a/source/tools/mudraw.c b/source/tools/mudraw.c index aebe441e..34f9778f 100644 --- a/source/tools/mudraw.c +++ b/source/tools/mudraw.c @@ -30,7 +30,7 @@ int gettimeofday(struct timeval *tv, struct timezone *tz); enum { OUT_NONE, OUT_PNG, OUT_TGA, OUT_PNM, OUT_PGM, OUT_PPM, OUT_PAM, - OUT_PBM, OUT_PKM, OUT_PWG, OUT_PCL, OUT_PS, + OUT_PBM, OUT_PKM, OUT_PWG, OUT_PCL, OUT_PS, OUT_PSD, OUT_TEXT, OUT_HTML, OUT_STEXT, OUT_TRACE, OUT_SVG, #if FZ_ENABLE_PDF @@ -59,10 +59,11 @@ static const suffix_t suffix_table[] = { ".svg", OUT_SVG }, { ".pwg", OUT_PWG }, { ".pcl", OUT_PCL }, - { ".ps", OUT_PS }, #if FZ_ENABLE_PDF { ".pdf", OUT_PDF }, #endif + { ".psd", OUT_PSD }, + { ".ps", OUT_PS }, { ".tga", OUT_TGA }, { ".txt", OUT_TEXT }, @@ -117,6 +118,7 @@ static const format_cs_table_t format_cs_table[] = { OUT_PWG, CS_RGB, { CS_MONO, CS_GRAY, CS_RGB, CS_CMYK } }, { OUT_PCL, CS_MONO, { CS_MONO, CS_RGB } }, { OUT_PS, CS_RGB, { CS_GRAY, CS_RGB, CS_CMYK } }, + { OUT_PSD, CS_CMYK, { CS_GRAY, CS_GRAY_ALPHA, CS_RGB, CS_RGB_ALPHA, CS_CMYK, CS_CMYK_ALPHA } }, { OUT_TGA, CS_RGB, { CS_GRAY, CS_GRAY_ALPHA, CS_RGB, CS_RGB_ALPHA } }, { OUT_TRACE, CS_RGB, { CS_RGB } }, @@ -787,6 +789,8 @@ static void dodrawpage(fz_context *ctx, fz_page *page, fz_display_list *list, in bander = fz_new_pkm_band_writer(ctx, out); else if (output_format == OUT_PS) bander = fz_new_ps_band_writer(ctx, out); + else if (output_format == OUT_PSD) + bander = fz_new_psd_band_writer(ctx, out); else if (output_format == OUT_TGA) bander = fz_new_tga_band_writer(ctx, out, colorspace == fz_device_bgr(ctx)); else if (output_format == OUT_PWG) @@ -1563,9 +1567,9 @@ int mudraw_main(int argc, char **argv) if (band_height) { - if (output_format != OUT_PAM && output_format != OUT_PGM && output_format != OUT_PPM && output_format != OUT_PNM && output_format != OUT_PNG && output_format != OUT_PBM && output_format != OUT_PKM && output_format != OUT_PCL && output_format != OUT_PS) + if (output_format != OUT_PAM && output_format != OUT_PGM && output_format != OUT_PPM && output_format != OUT_PNM && output_format != OUT_PNG && output_format != OUT_PBM && output_format != OUT_PKM && output_format != OUT_PCL && output_format != OUT_PS && output_format != OUT_PSD) { - fprintf(stderr, "Banded operation only possible with PAM, PBM, PGM, PKM, PPM, PNM, PCL, PS and PNG outputs\n"); + fprintf(stderr, "Banded operation only possible with PAM, PBM, PGM, PKM, PPM, PNM, PCL, PS, PSD and PNG outputs\n"); exit(1); } if (showmd5) |