Coverage Report

Created: 2022-10-31 07:00

/src/ghostpdl/devices/gdevpsd.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2022 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  1305 Grant Avenue - Suite 200, Novato,
13
   CA 94945, U.S.A., +1(415)492-9861, for further information.
14
*/
15
16
17
/* PhotoShop (PSD) export device, supporting DeviceN color models. */
18
19
#include "math_.h"
20
#include "gxiodev.h"
21
#include "gdevprn.h"
22
#include "gsparam.h"
23
#include "gscrd.h"
24
#include "gscrdp.h"
25
#include "gxlum.h"
26
#include "gdevdcrd.h"
27
#include "gstypes.h"
28
#include "gxdcconv.h"
29
#include "gdevdevn.h"
30
#include "gsequivc.h"
31
#include "gsicc_cache.h"
32
#include "gsicc_manage.h"
33
#include "gxgetbit.h"
34
#include "gdevppla.h"
35
#include "gxdownscale.h"
36
#include "gdevdevnprn.h"
37
#include "gdevpsd.h"
38
#include "gxdevsop.h"
39
#include "gsicc_cms.h"
40
41
#ifndef MAX_CHAN
42
#   define MAX_CHAN 15
43
#endif
44
45
/* Define the device parameters. */
46
#ifndef X_DPI
47
#  define X_DPI 72
48
#endif
49
#ifndef Y_DPI
50
#  define Y_DPI 72
51
#endif
52
53
#define ENABLE_COLOR_REPLACE 0
54
55
/* The device descriptor */
56
static dev_proc_open_device(psd_prn_open);
57
static dev_proc_close_device(psd_prn_close);
58
static dev_proc_get_params(psd_get_params);
59
static dev_proc_put_params(psd_put_params);
60
static dev_proc_get_params(psd_get_params_cmyk);
61
static dev_proc_put_params(psd_put_params_cmyk);
62
static dev_proc_put_params(psd_put_params_cmyktag);
63
static dev_proc_print_page(psd_print_page);
64
static dev_proc_map_color_rgb(psd_map_color_rgb);
65
static dev_proc_get_color_mapping_procs(get_psdrgb_color_mapping_procs);
66
static dev_proc_get_color_mapping_procs(get_psd_color_mapping_procs);
67
static dev_proc_get_color_comp_index(psd_get_color_comp_index);
68
69
/* This is redundant with color_info.cm_name. We may eliminate this
70
   typedef and use the latter string for everything. */
71
typedef enum {
72
    psd_DEVICE_GRAY,
73
    psd_DEVICE_RGB,
74
    psd_DEVICE_CMYK,
75
    psd_DEVICE_CMYKT,
76
    psd_DEVICE_N
77
} psd_color_model;
78
79
fixed_colorant_name DevCMYKTComponents[] = {
80
  "Cyan",
81
  "Magenta",
82
  "Yellow",
83
  "Black",
84
  "Tags",
85
  0               /* List terminator */
86
};
87
88
/*
89
 * A structure definition for a DeviceN type device
90
 */
91
typedef struct psd_device_s {
92
    gx_devn_prn_device_common;
93
94
    psd_color_model color_model;
95
96
    int max_spots;
97
    bool lock_colorants;
98
99
    gx_downscaler_params downscale;
100
101
    /* ICC color profile objects, for color conversion.
102
       These are all device link profiles.  At least that
103
       is how it appears looking at how this code
104
       was written to work with the old icclib.  Just
105
       doing minimal updates here so that it works
106
       with the new CMM API.  I would be interested
107
       to hear how people are using this. */
108
109
    char profile_rgb_fn[256];
110
    cmm_profile_t *rgb_profile;
111
    gcmmhlink_t rgb_icc_link;
112
113
    char profile_cmyk_fn[256];
114
    cmm_profile_t *cmyk_profile;
115
    gcmmhlink_t cmyk_icc_link;
116
117
    char profile_out_fn[256];
118
    cmm_profile_t *output_profile;
119
    gcmmhlink_t output_icc_link;
120
121
    bool warning_given;  /* Used to notify the user that max colorants reached */
122
123
#if ENABLE_COLOR_REPLACE
124
    bool color_replace_warning_given;
125
#endif
126
127
} psd_device;
128
129
/* GC procedures */
130
static
131
864k
ENUM_PTRS_WITH(psd_device_enum_ptrs, psd_device *pdev)
132
864k
{
133
864k
    ENUM_PREFIX(st_gx_devn_prn_device, 0);
134
0
    (void)pdev; /* Stop unused var warning */
135
0
    return 0;
136
0
}
137
864k
ENUM_PTRS_END
138
139
16.9k
static RELOC_PTRS_WITH(psd_device_reloc_ptrs, psd_device *pdev)
140
16.9k
{
141
16.9k
    RELOC_PREFIX(st_gx_devn_prn_device);
142
16.9k
    (void)pdev; /* Stop unused var warning */
143
16.9k
}
144
16.9k
RELOC_PTRS_END
145
146
static int
147
psd_spec_op(gx_device *dev_, int op, void *data, int datasize)
148
2.84M
{
149
2.84M
    if (op == gxdso_supports_devn || op == gxdso_skip_icc_component_validation) {
150
8.40k
        return true;
151
8.40k
    }
152
153
#if ENABLE_COLOR_REPLACE
154
    /* Demo of doing color replacement in the device in place of
155
       standard ICC color management */
156
    if (op == gxdso_replacecolor) {
157
158
        color_replace_t *replace_data = (color_replace_t *)data;
159
        gx_device_color *pdc = replace_data->pdc;
160
        const gs_color_space *pcs = replace_data->pcs;
161
        const gs_client_color *pcc = replace_data->pcc;
162
        const gs_gstate *pgs = replace_data->pgs;  /* Perhaps needed for named color profile information */
163
        psd_device* pdev_psd = (psd_device*)dev_;
164
165
        /* Just a warning here for now. When pdf14_profile is set, the user
166
           may need to do some extra work to get a desired color replacement.
167
           Note that the pdf14 color space can be completely different
168
           than the target device color space, which is what this will indicate.
169
           If the color space is gray or rgb we don't fool with any remap in this
170
           example. */
171
        if (replace_data->pdf14_iccprofile != NULL && !(pdev_psd->color_replace_warning_given)) {
172
            dmlprintf(pdev_psd->memory, "Warning. Doing color replacement for PDF14 device!\n");
173
            pdev_psd->color_replace_warning_given = true;
174
            if (replace_data->pdf14_iccprofile->num_comps == 3 ||
175
                replace_data->pdf14_iccprofile->num_comps == 1) {
176
                return false;
177
            }
178
        }
179
180
        /* CMYK or CIELAB source colors that are vector fills. */
181
        if ((pcs->cmm_icc_profile_data->data_cs == gsCMYK ||
182
             pcs->cmm_icc_profile_data->data_cs == gsCIELAB ||
183
             pcs->cmm_icc_profile_data->data_cs == gsRGB ) &&
184
            dev_->graphics_type_tag == GS_VECTOR_TAG) {
185
186
            int jj, ii;
187
            int values[4];
188
            int replace = 0;
189
190
            /* Zero out all the device values including any spots */
191
            for (ii = 0; ii < dev_->color_info.num_components; ii++) {
192
                pdc->colors.devn.values[ii] = 0;
193
            }
194
195
            if (pcs->cmm_icc_profile_data->data_cs == gsCMYK) {
196
197
                for (jj = 0; jj < 4; jj++) {
198
                    values[jj] = 65535 * pcc->paint.values[jj];
199
                }
200
201
                if (values[0] == 40959 && values[1] == 0 && values[2] == 11730 && values[3] == 0) {
202
                    replace = 1;
203
                    pdc->colors.devn.values[1] = 32000;
204
                } else if (values[0] == 0 && values[1] == 49741 && values[2] == 65535 && values[3] == 0) {
205
                    replace = 1;
206
                    pdc->colors.devn.values[0] = 48000;
207
                } else {
208
                    /* Test of shading.... */
209
                    replace = 1;
210
                    for (ii = 0; ii < 3; ii++) {
211
                        pdc->colors.devn.values[ii] = 65535 - values[ii];
212
                    }
213
                }
214
            } else if (pcs->cmm_icc_profile_data->data_cs == gsCIELAB) {
215
                /* CIELAB case.  Lets make color K only based upon luminance */
216
                int luminance = 65535 * pcc->paint.values[0] / 100.0;
217
                replace = 1;
218
219
                if (luminance > 65535)
220
                    luminance = 65535;
221
                pdc->colors.devn.values[3] = luminance;
222
            } else {
223
                /* Source is RGB case */
224
                /* Lets invert these as C = R, M = G, Y = B, K = 0 */
225
                replace = 1;
226
227
                for (ii = 0; ii < 3; ii++) {
228
                    pdc->colors.devn.values[ii] = 65535 * pcc->paint.values[ii];
229
                }
230
            }
231
232
            if (replace) {
233
                /* This is only for devn type devices. */
234
                pdc->type = gx_dc_type_devn;
235
236
                /* Save original color space and color info into dev color */
237
                ii = pcs->cmm_icc_profile_data->num_comps;
238
                for (ii--; ii >= 0; ii--)
239
                    pdc->ccolor.paint.values[ii] = pcc->paint.values[ii];
240
                pdc->ccolor_valid = true;
241
                return true;
242
            } else
243
                return false;  /* No replacement */
244
        } else
245
            return false;
246
    }
247
#endif
248
2.83M
    return gdev_prn_dev_spec_op(dev_, op, data, datasize);
249
2.84M
}
250
251
/* Even though psd_device_finalize is the same as gx_devn_prn_device_finalize,
252
 * we need to implement it separately because st_composite_final
253
 * declares all 3 procedures as private. */
254
static void
255
psd_device_finalize(const gs_memory_t *cmem, void *vpdev)
256
8.40k
{
257
8.40k
    gx_devn_prn_device_finalize(cmem, vpdev);
258
8.40k
}
259
260
gs_private_st_composite_final(st_psd_device, psd_device,
261
    "psd_device", psd_device_enum_ptrs, psd_device_reloc_ptrs,
262
    psd_device_finalize);
263
264
static void
265
psd_initialize_device_procs(gx_device *dev)
266
8.40k
{
267
8.40k
    gdev_prn_initialize_device_procs_bg(dev);
268
269
8.40k
    set_dev_proc(dev, open_device, psd_prn_open);
270
8.40k
    set_dev_proc(dev, close_device, psd_prn_close);
271
8.40k
    set_dev_proc(dev, map_color_rgb, psd_map_color_rgb);
272
8.40k
    set_dev_proc(dev, get_params, psd_get_params);
273
8.40k
    set_dev_proc(dev, put_params, psd_put_params);
274
8.40k
    set_dev_proc(dev, get_color_mapping_procs, get_psdrgb_color_mapping_procs);
275
8.40k
    set_dev_proc(dev, get_color_comp_index, psd_get_color_comp_index);
276
8.40k
    set_dev_proc(dev, encode_color, gx_devn_prn_encode_color);
277
8.40k
    set_dev_proc(dev, decode_color, gx_devn_prn_decode_color);
278
8.40k
    set_dev_proc(dev, update_spot_equivalent_colors, gx_devn_prn_update_spot_equivalent_colors);
279
8.40k
    set_dev_proc(dev, ret_devn_params, gx_devn_prn_ret_devn_params);
280
8.40k
    set_dev_proc(dev, dev_spec_op, psd_spec_op);
281
8.40k
}
282
283
#define psd_device_body(procs, dname, ncomp, pol, depth, mg, mc, sl, cn)\
284
    std_device_full_body_type_extended(psd_device, &procs, dname,\
285
          &st_psd_device,\
286
          (int)((long)(DEFAULT_WIDTH_10THS) * (X_DPI) / 10),\
287
          (int)((long)(DEFAULT_HEIGHT_10THS) * (Y_DPI) / 10),\
288
          X_DPI, Y_DPI,\
289
          GX_DEVICE_COLOR_MAX_COMPONENTS, /* MaxComponents */\
290
          ncomp,    /* NumComp */\
291
          pol,      /* Polarity */\
292
          depth, 0,   /* Depth, GrayIndex */\
293
          mg, mc,   /* MaxGray, MaxColor */\
294
          mg + 1, mc + 1, /* DitherGray, DitherColor */\
295
          sl,     /* Linear & Separable? */\
296
          cn,     /* Process color model name */\
297
          0, 0,     /* offsets */\
298
          0, 0, 0, 0    /* margins */\
299
        ),\
300
        prn_device_body_rest_(psd_print_page)
301
302
/*
303
 * PSD device with RGB process color model.
304
 */
305
const psd_device gs_psdrgb_device =
306
{
307
    psd_device_body(psd_initialize_device_procs, "psdrgb", 3, GX_CINFO_POLARITY_ADDITIVE, 24, 255, 255, GX_CINFO_SEP_LIN, "DeviceRGB"),
308
    /* devn_params specific parameters */
309
    { 8,  /* Bits per color - must match ncomp, depth, etc. above */
310
      DeviceRGBComponents,  /* Names of color model colorants */
311
      3,      /* Number colorants for RGB */
312
      0,      /* MaxSeparations has not been specified */
313
      -1,     /* PageSpotColors has not been specified */
314
      {0},      /* SeparationNames */
315
      0,      /* SeparationOrder names */
316
      {0, 1, 2, 3, 4, 5, 6, 7 } /* Initial component SeparationOrder */
317
    },
318
    { true },     /* equivalent CMYK colors for spot colors */
319
    /* PSD device specific parameters */
320
    psd_DEVICE_RGB,   /* Color model */
321
    GS_SOFT_MAX_SPOTS,    /* max_spots */
322
    false,                      /* colorants not locked */
323
    GX_DOWNSCALER_PARAMS_DEFAULTS
324
};
325
326
const psd_device gs_psdrgb16_device =
327
{
328
    psd_device_body(psd_initialize_device_procs, "psdrgb16", 3, GX_CINFO_POLARITY_ADDITIVE, 48, 65535, 65535, GX_CINFO_SEP_LIN, "DeviceRGB"),
329
    /* devn_params specific parameters */
330
    { 16, /* Bits per color - must match ncomp, depth, etc. above */
331
      DeviceRGBComponents,  /* Names of color model colorants */
332
      3,      /* Number colorants for RGB */
333
      0,      /* MaxSeparations has not been specified */
334
      -1,     /* PageSpotColors has not been specified */
335
      { 0 },      /* SeparationNames */
336
      0,      /* SeparationOrder names */
337
      {0, 1, 2, 3, 4, 5, 6, 7 } /* Initial component SeparationOrder */
338
    },
339
    { true },     /* equivalent CMYK colors for spot colors */
340
    /* PSD device specific parameters */
341
    psd_DEVICE_RGB,   /* Color model */
342
    GS_SOFT_MAX_SPOTS,           /* max_spots */
343
    false,                      /* colorants not locked */
344
    GX_DOWNSCALER_PARAMS_DEFAULTS
345
};
346
347
/*
348
 * PSD device with CMYK process color model and spot color support.
349
 */
350
static void
351
psdcmyk_initialize_device_procs(gx_device *dev)
352
8.40k
{
353
8.40k
    psd_initialize_device_procs(dev);
354
355
8.40k
    set_dev_proc(dev, get_params, psd_get_params_cmyk);
356
8.40k
    set_dev_proc(dev, put_params, psd_put_params_cmyk);
357
8.40k
    set_dev_proc(dev, get_color_mapping_procs, get_psd_color_mapping_procs);
358
8.40k
}
359
360
/*
361
 * PSD device with CMYK process color model, spot color support, and tags.
362
 */
363
static void
364
psdcmyktag_initialize_device_procs(gx_device *dev)
365
0
{
366
0
    psd_initialize_device_procs(dev);
367
368
0
    set_dev_proc(dev, get_params, psd_get_params_cmyk);
369
0
    set_dev_proc(dev, put_params, psd_put_params_cmyktag);
370
0
    set_dev_proc(dev, get_color_mapping_procs, get_psd_color_mapping_procs);
371
0
}
372
373
const psd_device gs_psdcmyk_device =
374
{
375
    psd_device_body(psdcmyk_initialize_device_procs, "psdcmyk",
376
                    ARCH_SIZEOF_GX_COLOR_INDEX, /* Number of components - need a nominal 1 bit for each */
377
                    GX_CINFO_POLARITY_SUBTRACTIVE,
378
                    ARCH_SIZEOF_GX_COLOR_INDEX * 8, /* 8 bits per component (albeit in planes) */
379
                    255, 255, GX_CINFO_SEP_LIN, "DeviceCMYK"),
380
    /* devn_params specific parameters */
381
    { 8,  /* Bits per color - must match ncomp, depth, etc. above */
382
      DeviceCMYKComponents, /* Names of color model colorants */
383
      4,      /* Number colorants for CMYK */
384
      0,      /* MaxSeparations has not been specified */
385
      -1,     /* PageSpotColors has not been specified */
386
      {0},      /* SeparationNames */
387
      0,      /* SeparationOrder names */
388
      {0, 1, 2, 3, 4, 5, 6, 7 } /* Initial component SeparationOrder */
389
    },
390
    { true },     /* equivalent CMYK colors for spot colors */
391
    /* PSD device specific parameters */
392
    psd_DEVICE_CMYK,    /* Color model */
393
    GS_SOFT_MAX_SPOTS,          /* max_spots */
394
    false,                      /* colorants not locked */
395
    GX_DOWNSCALER_PARAMS_DEFAULTS
396
};
397
398
const psd_device gs_psdcmyktags_device =
399
{
400
    psd_device_body(psdcmyktag_initialize_device_procs, "psdcmyktags",
401
                    ARCH_SIZEOF_GX_COLOR_INDEX, /* Number of components - need a nominal 1 bit for each */
402
                    GX_CINFO_POLARITY_SUBTRACTIVE,
403
                    ARCH_SIZEOF_GX_COLOR_INDEX * 8, /* 8 bits per component (albeit in planes) */
404
                    255, 255, GX_CINFO_SEP_LIN, "DeviceCMYK"),
405
    /* devn_params specific parameters */
406
    { 8,      /* Bits per color - must match ncomp, depth, etc. above */
407
      DevCMYKTComponents, /* Names of color model colorants */
408
      4,      /* Number colorants for CMYK. Tags added to extra in DevCMYKTComponents */
409
      0,      /* MaxSeparations has not been specified */
410
      -1,     /* PageSpotColors has not been specified */
411
      {0},      /* SeparationNames */
412
      0,      /* SeparationOrder names */
413
      {0, 1, 2, 3, 4, 5, 6, 7 } /* Initial component SeparationOrder */
414
    },
415
    { true },     /* equivalent CMYK colors for spot colors */
416
    /* PSD device specific parameters */
417
    psd_DEVICE_CMYKT,   /* Color model */
418
    GS_SOFT_MAX_SPOTS,          /* max_spots */
419
    false,                      /* colorants not locked */
420
    GX_DOWNSCALER_PARAMS_DEFAULTS
421
};
422
423
const psd_device gs_psdcmyk16_device =
424
{
425
    psd_device_body(psdcmyk_initialize_device_procs, "psdcmyk16",
426
                    ARCH_SIZEOF_GX_COLOR_INDEX, /* Number of components - need a nominal 1 bit for each */
427
                    GX_CINFO_POLARITY_SUBTRACTIVE,
428
                    ARCH_SIZEOF_GX_COLOR_INDEX * 16, /* 8 bits per component (albeit in planes) */
429
                    65535, 65535, GX_CINFO_SEP_LIN, "DeviceCMYK"),
430
    /* devn_params specific parameters */
431
    { 16, /* Bits per color - must match ncomp, depth, etc. above */
432
      DeviceCMYKComponents, /* Names of color model colorants */
433
      4,      /* Number colorants for CMYK */
434
      0,      /* MaxSeparations has not been specified */
435
      -1,     /* PageSpotColors has not been specified */
436
      { 0 },      /* SeparationNames */
437
      0,      /* SeparationOrder names */
438
      {0, 1, 2, 3, 4, 5, 6, 7 } /* Initial component SeparationOrder */
439
    },
440
    { true },     /* equivalent CMYK colors for spot colors */
441
    /* PSD device specific parameters */
442
    psd_DEVICE_CMYK,    /* Color model */
443
    GS_SOFT_MAX_SPOTS,          /* max_spots */
444
    false,                      /* colorants not locked */
445
    GX_DOWNSCALER_PARAMS_DEFAULTS
446
};
447
448
const psd_device gs_psdcmyktags16_device =
449
{
450
    psd_device_body(psdcmyktag_initialize_device_procs, "psdcmyktags16",
451
                    ARCH_SIZEOF_GX_COLOR_INDEX, /* Number of components - need a nominal 1 bit for each */
452
                    GX_CINFO_POLARITY_SUBTRACTIVE,
453
                    ARCH_SIZEOF_GX_COLOR_INDEX * 16, /* 8 bits per component (albeit in planes) */
454
                    65535, 65535, GX_CINFO_SEP_LIN, "DeviceCMYK"),
455
    /* devn_params specific parameters */
456
    { 16, /* Bits per color - must match ncomp, depth, etc. above */
457
      DevCMYKTComponents, /* Names of color model colorants */
458
      4,      /* Number colorants for CMYK. Tags added to extra in DevCMYKTComponents */
459
      0,      /* MaxSeparations has not been specified */
460
      -1,     /* PageSpotColors has not been specified */
461
      { 0 },      /* SeparationNames */
462
      0,      /* SeparationOrder names */
463
      {0, 1, 2, 3, 4, 5, 6, 7 } /* Initial component SeparationOrder */
464
    },
465
    { true },     /* equivalent CMYK colors for spot colors */
466
    /* PSD device specific parameters */
467
    psd_DEVICE_CMYKT,   /* Color model */
468
    GS_SOFT_MAX_SPOTS,          /* max_spots */
469
    false,                      /* colorants not locked */
470
    GX_DOWNSCALER_PARAMS_DEFAULTS
471
};
472
473
/* Open the psd devices */
474
int
475
psd_prn_open(gx_device * pdev)
476
13.5k
{
477
13.5k
    psd_device *pdev_psd = (psd_device *) pdev;
478
13.5k
    int code;
479
13.5k
    int k;
480
13.5k
    cmm_dev_profile_t *profile_struct;
481
13.5k
    bool has_tags = (pdev_psd->color_model == psd_DEVICE_CMYKT);
482
483
#ifdef TEST_PAD_AND_ALIGN
484
    pdev->pad = 5;
485
    pdev->log2_align_mod = 6;
486
#endif
487
13.5k
    code = dev_proc(pdev, get_profile)((gx_device *)pdev, &profile_struct);
488
489
13.5k
    pdev_psd->warning_given = false;
490
491
#if ENABLE_COLOR_REPLACE
492
    pdev_psd->color_replace_warning_given = false;
493
#endif
494
495
    /* For the planar device we need to set up the bit depth of each plane.
496
       For other devices this is handled in check_device_separable where
497
       we compute the bit shift for the components etc. */
498
877k
    for (k = 0; k < GS_CLIENT_COLOR_MAX_COMPONENTS; k++) {
499
864k
        pdev->color_info.comp_bits[k] = 8;
500
864k
    }
501
502
    /* With planar the depth can be more than 64.  Update the color
503
       info to reflect the proper depth and number of planes.  Also note
504
       that the number of spot colors can change from page to page.
505
       Update things so that we only output separations for the
506
       inks on that page. */
507
13.5k
    if (pdev->color_info.polarity == GX_CINFO_POLARITY_SUBTRACTIVE) {
508
13.5k
        if (pdev_psd->devn_params.page_spot_colors >= 0) {
509
510
            /* PDF case, as the page spot colors are known. */
511
2.55k
            if (profile_struct->spotnames != NULL) {
512
513
                /* PDF case, NCLR ICC profile with spot names. The ICC spots
514
                   will use up some of the max_spots values. If max_spots is
515
                   too small to accomodate even the ICC spots, throw an error */
516
0
                if (profile_struct->spotnames->count - 4 > pdev_psd->max_spots ||
517
0
                        profile_struct->spotnames->count < 4 ||
518
0
                        profile_struct->spotnames->count <
519
0
                        profile_struct->device_profile[0]->num_comps) {
520
0
                    gs_warn("ICC profile colorant names count error");
521
0
                    return_error(gs_error_rangecheck);
522
0
                }
523
0
                pdev->color_info.num_components =
524
0
                    (profile_struct->spotnames->count
525
0
                    + pdev_psd->devn_params.page_spot_colors + has_tags);
526
0
                if (pdev->color_info.num_components > pdev->color_info.max_components)
527
0
                    pdev->color_info.num_components = pdev->color_info.max_components;
528
2.55k
            } else {
529
530
                /* Use the information that is in the page spot color. We should
531
                   be here if we are processing a PDF and we do not have a DeviceN
532
                   ICC profile specified for output */
533
2.55k
                if (!(pdev_psd->lock_colorants)) {
534
2.55k
                    pdev->color_info.num_components =
535
2.55k
                        (pdev_psd->devn_params.page_spot_colors
536
2.55k
                        + pdev_psd->devn_params.num_std_colorant_names + has_tags);
537
2.55k
                    if (pdev->color_info.num_components > pdev->color_info.max_components)
538
0
                        pdev->color_info.num_components = pdev->color_info.max_components;
539
2.55k
                }
540
2.55k
            }
541
10.9k
        } else {
542
543
            /* We do not know how many spots may occur on the page.
544
               For this reason we go ahead and allocate the maximum that we
545
               have available.  Note, lack of knowledge only occurs in the case
546
               of PS files. With PDF we know a priori the number of spot
547
               colorants. However, the first time the device is opened,
548
               pdev_psd->devn_params.page_spot_colors is -1 even if we are
549
               dealing with a PDF file, so we will first find ourselves here,
550
               which will set num_comp based upon max_spots + 4. If -dMaxSpots
551
               was set (Default is GS_SOFT_MAX_SPOTS which is 10),
552
               it is made use of here. */
553
10.9k
            if (!(pdev_psd->lock_colorants)) {
554
10.9k
                int num_comp = pdev_psd->max_spots + 4 + has_tags; /* Spots + CMYK */
555
10.9k
                if (num_comp > GS_CLIENT_COLOR_MAX_COMPONENTS)
556
0
                    num_comp = GS_CLIENT_COLOR_MAX_COMPONENTS;
557
10.9k
                pdev->color_info.num_components = num_comp;
558
10.9k
                pdev->color_info.max_components = num_comp;
559
10.9k
            }
560
10.9k
        }
561
13.5k
    }
562
    /* Push this to the max amount as a default if someone has not set it */
563
13.5k
    if (pdev_psd->devn_params.num_separation_order_names == 0)
564
877k
        for (k = 0; k < GS_CLIENT_COLOR_MAX_COMPONENTS; k++) {
565
864k
            pdev_psd->devn_params.separation_order_map[k] = k;
566
864k
        }
567
13.5k
    pdev->color_info.depth = pdev->color_info.num_components *
568
13.5k
                             pdev_psd->devn_params.bitspercomponent;
569
13.5k
    pdev->color_info.separable_and_linear = GX_CINFO_SEP_LIN;
570
13.5k
    set_linear_color_bits_mask_shift(pdev);
571
13.5k
    if (pdev->color_info.polarity == GX_CINFO_POLARITY_ADDITIVE)
572
0
        pdev->icc_struct->supports_devn = false;
573
13.5k
    else
574
13.5k
        pdev->icc_struct->supports_devn = true;
575
13.5k
    code = gdev_prn_open_planar(pdev, true);
576
13.5k
    return code;
577
13.5k
}
578
579
/* 2007/05/04
580
psdgray device
581
*/
582
static void
583
gray_cs_to_psdgray_cm(const gx_device * dev, frac gray, frac out[])
584
0
{
585
0
    out[0] = gray;
586
0
}
587
588
static void
589
rgb_cs_to_psdgray_cm(const gx_device * dev, const gs_gstate *pgs,
590
                                   frac r, frac g, frac b, frac out[])
591
0
{
592
0
    out[0] = color_rgb_to_gray(r, g, b, NULL);
593
0
}
594
595
static void
596
cmyk_cs_to_psdgray_cm(const gx_device * dev, frac c, frac m, frac y, frac k, frac out[])
597
0
{
598
0
    out[0] = color_cmyk_to_gray(c, m, y, k, NULL);
599
0
}
600
601
/*
602
 * The following procedures are used to map the standard color spaces into
603
 * the color components for the psdrgb device.
604
 */
605
static void
606
gray_cs_to_psdrgb_cm(const gx_device * dev, frac gray, frac out[])
607
0
{
608
0
    int i = ((psd_device *)dev)->devn_params.separations.num_separations;
609
610
0
    out[0] = out[1] = out[2] = gray;
611
0
    for(; i>0; i--)     /* Clear spot colors */
612
0
        out[2 + i] = 0;
613
0
}
614
615
static void
616
rgb_cs_to_psdrgb_cm(const gx_device * dev, const gs_gstate *pgs,
617
                                  frac r, frac g, frac b, frac out[])
618
0
{
619
0
    int i = ((psd_device *)dev)->devn_params.separations.num_separations;
620
621
0
    out[0] = r;
622
0
    out[1] = g;
623
0
    out[2] = b;
624
0
    for(; i>0; i--)     /* Clear spot colors */
625
0
        out[2 + i] = 0;
626
0
}
627
628
static void
629
cmyk_cs_to_psdrgb_cm(const gx_device * dev,
630
                        frac c, frac m, frac y, frac k, frac out[])
631
0
{
632
0
    int i = ((psd_device *)dev)->devn_params.separations.num_separations;
633
634
0
    color_cmyk_to_rgb(c, m, y, k, NULL, out, dev->memory);
635
0
    for(; i>0; i--)     /* Clear spot colors */
636
0
        out[2 + i] = 0;
637
0
}
638
639
/* Color mapping routines for the psdcmyk device */
640
641
static void
642
gray_cs_to_psdcmyk_cm(const gx_device * dev, frac gray, frac out[])
643
218
{
644
218
    int * map = ((psd_device *) dev)->devn_params.separation_order_map;
645
646
218
    gray_cs_to_devn_cm(dev, map, gray, out);
647
218
}
648
649
static void
650
rgb_cs_to_psdcmyk_cm(const gx_device * dev, const gs_gstate *pgs,
651
                           frac r, frac g, frac b, frac out[])
652
0
{
653
0
    int * map = ((psd_device *) dev)->devn_params.separation_order_map;
654
655
0
    rgb_cs_to_devn_cm(dev, map, pgs, r, g, b, out);
656
0
}
657
658
static void
659
cmyk_cs_to_psdcmyktags_cm(const gx_device *dev,
660
                          frac c, frac m, frac y, frac k, frac out[])
661
0
{
662
0
    const gs_devn_params *devn = gx_devn_prn_ret_devn_params_const(dev);
663
0
    const int *map = devn->separation_order_map;
664
0
    int j;
665
0
    int ncomps = dev->color_info.num_components;
666
667
0
    if (devn->num_separation_order_names > 0) {
668
        /* This is to set only those that we are using */
669
0
        for (j = 0; j < ncomps; j++)
670
0
            out[j] = 0;
671
0
        for (j = 0; j < devn->num_separation_order_names; j++) {
672
0
            switch (map[j]) {
673
0
            case 0:
674
0
                out[0] = c;
675
0
                break;
676
0
            case 1:
677
0
                out[1] = m;
678
0
                break;
679
0
            case 2:
680
0
                out[2] = y;
681
0
                break;
682
0
            case 3:
683
0
                out[3] = k;
684
0
                break;
685
0
            default:
686
0
                break;
687
0
            }
688
0
        }
689
0
    } else {
690
0
        cmyk_cs_to_devn_cm(dev, map, c, m, y, k, out);
691
0
    }
692
    /* And set the tags. At this point, the color values
693
       are frac representation for the range [0.0 1.0]. We
694
       need to encode the graphics type, which is 0 to 255
695
       accordingly, as it goes through the same mappings on
696
       its way to devn and then eventually to 8 or 16 bit values */
697
0
    if (map[ncomps - 1] != GX_DEVICE_COLOR_MAX_COMPONENTS)
698
0
        out[ncomps - 1] = byte2frac(dev->graphics_type_tag & ~GS_DEVICE_ENCODES_TAGS);
699
0
}
700
701
static void
702
cmyk_cs_to_psdcmyk_cm(const gx_device * dev,
703
                        frac c, frac m, frac y, frac k, frac out[])
704
1.70M
{
705
1.70M
    const gs_devn_params *devn = gx_devn_prn_ret_devn_params_const(dev);
706
1.70M
    const int *map = devn->separation_order_map;
707
1.70M
    int j;
708
709
1.70M
    if (devn->num_separation_order_names > 0) {
710
        /* This is to set only those that we are using */
711
0
        int ncomps = dev->color_info.num_components;
712
0
        for (j = 0; j < ncomps; j++)
713
0
            out[j] = 0;
714
0
        for (j = 0; j < devn->num_separation_order_names; j++) {
715
0
            switch (map[j]) {
716
0
                case 0 :
717
0
                    out[0] = c;
718
0
                    break;
719
0
                case 1:
720
0
                    out[1] = m;
721
0
                    break;
722
0
                case 2:
723
0
                    out[2] = y;
724
0
                    break;
725
0
                case 3:
726
0
                    out[3] = k;
727
0
                    break;
728
0
                default:
729
0
                    break;
730
0
            }
731
0
        }
732
1.70M
    } else {
733
1.70M
        cmyk_cs_to_devn_cm(dev, map, c, m, y, k, out);
734
1.70M
    }
735
1.70M
}
736
737
static void
738
cmyk_cs_to_spotn_cm(const gx_device * dev, frac c, frac m, frac y, frac k, frac out[])
739
0
{
740
0
    psd_device *xdev = (psd_device *)dev;
741
0
    int n = xdev->devn_params.separations.num_separations;
742
743
0
    gcmmhlink_t link = xdev->cmyk_icc_link;
744
0
    int i;
745
746
0
    if (link != NULL) {
747
748
0
        unsigned short in[4];
749
0
        unsigned short tmp[MAX_CHAN];
750
0
        int outn = xdev->cmyk_profile->num_comps_out;
751
752
0
        in[0] = frac2ushort(c);
753
0
        in[1] = frac2ushort(m);
754
0
        in[2] = frac2ushort(y);
755
0
        in[3] = frac2ushort(k);
756
757
0
        gscms_transform_color_const(dev, link, &(in[0]),
758
0
                        &(tmp[0]), 2);
759
760
0
        for (i = 0; i < outn; i++)
761
0
            out[i] = ushort2frac(tmp[i]);
762
0
        for (; i < n + 4; i++)
763
0
            out[i] = 0;
764
765
0
    } else {
766
        /* If no profile given, assume CMYK */
767
0
        out[0] = c;
768
0
        out[1] = m;
769
0
        out[2] = y;
770
0
        out[3] = k;
771
0
        for(i = 0; i < n; i++)     /* Clear spot colors */
772
0
            out[4 + i] = 0;
773
0
    }
774
0
}
775
776
static void
777
gray_cs_to_spotn_cm(const gx_device * dev, frac gray, frac out[])
778
0
{
779
0
    cmyk_cs_to_spotn_cm(dev, 0, 0, 0, (frac)(frac_1 - gray), out);
780
0
}
781
782
static void
783
rgb_cs_to_spotn_cm(const gx_device * dev, const gs_gstate *pgs,
784
                                   frac r, frac g, frac b, frac out[])
785
0
{
786
0
    psd_device *xdev = (psd_device *)dev;
787
0
    int n = xdev->devn_params.separations.num_separations;
788
0
    gcmmhlink_t link = xdev->rgb_icc_link;
789
0
    int i;
790
791
0
    if (link != NULL) {
792
793
0
        unsigned short in[3];
794
0
        unsigned short tmp[MAX_CHAN];
795
0
        int outn = xdev->rgb_profile->num_comps_out;
796
797
0
        in[0] = frac2ushort(r);
798
0
        in[1] = frac2ushort(g);
799
0
        in[2] = frac2ushort(b);
800
801
0
        gscms_transform_color_const(dev, link, &(in[0]),
802
0
                        &(tmp[0]), 2);
803
804
0
        for (i = 0; i < outn; i++)
805
0
            out[i] = ushort2frac(tmp[i]);
806
0
        for (; i < n + 4; i++)
807
0
            out[i] = 0;
808
809
0
    } else {
810
0
        frac cmyk[4];
811
812
0
        color_rgb_to_cmyk(r, g, b, pgs, cmyk, dev->memory);
813
0
        cmyk_cs_to_spotn_cm(dev, cmyk[0], cmyk[1], cmyk[2], cmyk[3],
814
0
                            out);
815
0
    }
816
0
}
817
818
static const gx_cm_color_map_procs psdGray_procs = {/* 2007/05/04 Test */
819
    gray_cs_to_psdgray_cm, rgb_cs_to_psdgray_cm, cmyk_cs_to_psdgray_cm
820
};
821
822
static const gx_cm_color_map_procs psdRGB_procs = {
823
    gray_cs_to_psdrgb_cm, rgb_cs_to_psdrgb_cm, cmyk_cs_to_psdrgb_cm
824
};
825
826
static const gx_cm_color_map_procs psdCMYK_procs = {
827
    gray_cs_to_psdcmyk_cm, rgb_cs_to_psdcmyk_cm, cmyk_cs_to_psdcmyk_cm
828
};
829
830
static const gx_cm_color_map_procs psdCMYKtags_procs = {
831
    gray_cs_to_psdcmyk_cm, rgb_cs_to_psdcmyk_cm, cmyk_cs_to_psdcmyktags_cm
832
};
833
834
static const gx_cm_color_map_procs psdN_procs = {
835
    gray_cs_to_spotn_cm, rgb_cs_to_spotn_cm, cmyk_cs_to_spotn_cm
836
};
837
838
/*
839
 * These are the handlers for returning the list of color space
840
 * to color model conversion routines.
841
 */
842
static const gx_cm_color_map_procs *
843
get_psdrgb_color_mapping_procs(const gx_device * dev, const gx_device **map_dev)
844
0
{
845
0
    *map_dev = dev;
846
0
    return &psdRGB_procs;
847
0
}
848
849
static const gx_cm_color_map_procs *
850
get_psd_color_mapping_procs(const gx_device * dev, const gx_device **map_dev)
851
1.70M
{
852
1.70M
    const psd_device *xdev = (const psd_device *)dev;
853
854
1.70M
    *map_dev = dev;
855
1.70M
    if (xdev->color_model == psd_DEVICE_RGB)
856
0
        return &psdRGB_procs;
857
1.70M
    else if (xdev->color_model == psd_DEVICE_CMYK)
858
1.70M
        return &psdCMYK_procs;
859
0
    else if (xdev->color_model == psd_DEVICE_CMYKT)
860
0
        return &psdCMYKtags_procs;
861
0
    else if (xdev->color_model == psd_DEVICE_N)
862
0
        return &psdN_procs;
863
0
    else if (xdev->color_model == psd_DEVICE_GRAY)
864
0
        return &psdGray_procs;
865
0
    else
866
0
        return NULL;
867
1.70M
}
868
869
/*
870
 * Convert a gx_color_index to RGB.
871
 */
872
static int
873
psd_map_color_rgb(gx_device *dev, gx_color_index color, gx_color_value rgb[3])
874
0
{
875
0
    psd_device *xdev = (psd_device *)dev;
876
877
0
    if (xdev->color_model == psd_DEVICE_RGB)
878
0
        return gx_devn_prn_decode_color(dev, color, rgb);
879
    /* TODO: return reasonable values. */
880
0
    rgb[0] = 0;
881
0
    rgb[1] = 0;
882
0
    rgb[2] = 0;
883
0
    return 0;
884
0
}
885
886
/* Get parameters.  We provide a default CRD. */
887
static int
888
psd_get_params_generic(gx_device * pdev, gs_param_list * plist, int cmyk)
889
132k
{
890
132k
    psd_device *xdev = (psd_device *)pdev;
891
132k
    int code;
892
893
132k
    code = gx_devn_prn_get_params(pdev, plist);
894
132k
    if (code < 0)
895
0
        return code;
896
897
132k
    code = gx_downscaler_write_params(plist, &xdev->downscale,
898
132k
                                      cmyk ? GX_DOWNSCALER_PARAMS_TRAP : 0);
899
132k
    if (code < 0)
900
0
        return code;
901
132k
    code = param_write_int(plist, "MaxSpots", &xdev->max_spots);
902
132k
    if (code < 0)
903
0
        return code;
904
132k
    code = param_write_bool(plist, "LockColorants", &xdev->lock_colorants);
905
132k
    return code;
906
132k
}
907
908
static int
909
psd_get_params(gx_device * pdev, gs_param_list * plist)
910
0
{
911
0
    return psd_get_params_generic(pdev, plist, 0);
912
0
}
913
914
static int
915
psd_get_params_cmyk(gx_device * pdev, gs_param_list * plist)
916
132k
{
917
132k
    return psd_get_params_generic(pdev, plist, 1);
918
132k
}
919
920
/* Set parameters.  We allow setting the number of bits per component. */
921
static int
922
psd_put_params_generic(gx_device * pdev, gs_param_list * plist, int cmyk)
923
39.0k
{
924
39.0k
    psd_device * const pdevn = (psd_device *) pdev;
925
39.0k
    int code = 0;
926
927
39.0k
    code = gx_downscaler_read_params(plist, &pdevn->downscale,
928
39.0k
                                     cmyk ? GX_DOWNSCALER_PARAMS_TRAP : 0);
929
39.0k
    if (code < 0)
930
0
        return code;
931
932
39.0k
    switch (code = param_read_bool(plist, "LockColorants", &(pdevn->lock_colorants))) {
933
2.54k
        case 0:
934
2.54k
            break;
935
36.5k
        case 1:
936
36.5k
            break;
937
0
        default:
938
0
            param_signal_error(plist, "LockColorants", code);
939
0
            return code;
940
39.0k
    }
941
942
39.0k
    switch (code = param_read_int(plist,
943
39.0k
                                  "MaxSpots",
944
39.0k
                                  &pdevn->max_spots)) {
945
2.54k
        case 0:
946
2.54k
            if (pdevn->max_spots >= 0 && pdevn->max_spots <= GS_CLIENT_COLOR_MAX_COMPONENTS-4)
947
2.54k
                break;
948
0
            emprintf1(pdevn->memory, "MaxSpots must be between 0 and %d\n",
949
0
                      GS_CLIENT_COLOR_MAX_COMPONENTS-4);
950
0
            code = gs_note_error(gs_error_rangecheck);
951
            /* fall through */
952
0
        default:
953
0
            param_signal_error(plist, "MaxSpots", code);
954
0
            return code;
955
36.5k
        case 1:
956
36.5k
            break;
957
39.0k
    }
958
959
    /* handle the standard DeviceN related parameters */
960
39.0k
    if (code >= 0)
961
39.0k
        code = gx_devn_prn_put_params(pdev, plist);
962
963
39.0k
    return code;
964
39.0k
}
965
966
static int
967
psd_put_params(gx_device * pdev, gs_param_list * plist)
968
0
{
969
0
    return psd_put_params_generic(pdev, plist, 0);
970
0
}
971
972
static int
973
psd_put_params_cmyk(gx_device * pdev, gs_param_list * plist)
974
39.0k
{
975
39.0k
    return psd_put_params_generic(pdev, plist, 1);
976
39.0k
}
977
978
static int
979
psd_put_params_cmyktag(gx_device *pdev, gs_param_list* plist)
980
0
{
981
0
    pdev->graphics_type_tag |= GS_DEVICE_ENCODES_TAGS;
982
0
    return psd_put_params_generic(pdev, plist, 1);
983
0
}
984
985
/*
986
 * This routine will check to see if the color component name  match those
987
 * that are available amoung the current device's color components.
988
 *
989
 * Parameters:
990
 *   dev - pointer to device data structure.
991
 *   pname - pointer to name (zero termination not required)
992
 *   nlength - length of the name
993
 *
994
 * This routine returns a positive value (0 to n) which is the device colorant
995
 * number if the name is found.  It returns a negative value if not found.
996
 */
997
static int
998
psd_get_color_comp_index(gx_device * dev, const char * pname,
999
                                        int name_size, int component_type)
1000
175k
{
1001
175k
    int index;
1002
175k
    psd_device *pdev = (psd_device *)dev;
1003
1004
175k
    if (strncmp(pname, "None", name_size) == 0) return -1;
1005
175k
    index = gx_devn_prn_get_color_comp_index(dev, pname, name_size,
1006
175k
                                             component_type);
1007
    /* This is a one shot deal.  That is it will simply post a notice once that
1008
       some colorants will be converted due to a limit being reached.  It will
1009
       not list names of colorants since then I would need to keep track of
1010
       which ones I have already mentioned.  Also, if someone is fooling with
1011
       num_order, then this warning is not given since they should know what
1012
       is going on already */
1013
175k
    if (index < 0 && component_type == SEPARATION_NAME &&
1014
175k
        pdev->warning_given == false &&
1015
175k
        pdev->devn_params.num_separation_order_names == 0) {
1016
0
        dmlprintf(dev->memory, "**** Max spot colorants reached.\n");
1017
0
        dmlprintf(dev->memory, "**** Some colorants will be converted to equivalent CMYK values.\n");
1018
0
        dmlprintf(dev->memory, "**** If this is a Postscript file, try using the -dMaxSpots= option.\n");
1019
0
        pdev->warning_given = true;
1020
0
    }
1021
175k
    return index;
1022
175k
}
1023
1024
/* ------ Private definitions ------ */
1025
1026
/* All two-byte quantities are stored MSB-first! */
1027
#if ARCH_IS_BIG_ENDIAN
1028
#  define assign_u16(a,v) a = (v)
1029
#  define assign_u32(a,v) a = (v)
1030
#else
1031
72.3k
#  define assign_u16(a,v) a = ((v) >> 8) + ((v) << 8)
1032
47.9k
#  define assign_u32(a,v) a = (((v) >> 24) & 0xff) + (((v) >> 8) & 0xff00) + (((v) & 0xff00) << 8) + (((v) & 0xff) << 24)
1033
#endif
1034
1035
int
1036
psd_setup(psd_write_ctx *xc, gx_devn_prn_device *dev, gp_file *file, int w, int h)
1037
3.99k
{
1038
3.99k
    int i;
1039
3.99k
    int spot_count;
1040
1041
3.99k
    xc->f = file;
1042
1043
24.1k
#define NUM_CMYK_COMPONENTS 4
1044
19.9k
    for (i = 0; i < GX_DEVICE_COLOR_MAX_COMPONENTS; i++) {
1045
19.9k
        if (dev->devn_params.std_colorant_names[i] == NULL)
1046
3.99k
            break;
1047
19.9k
    }
1048
3.99k
    xc->base_num_channels = dev->devn_params.num_std_colorant_names;
1049
3.99k
    xc->num_channels = i;
1050
3.99k
    if (dev->color_info.polarity == GX_CINFO_POLARITY_SUBTRACTIVE
1051
3.99k
        && strcmp(dev->dname, "psdcmykog") != 0) {
1052
1053
        /* Note: num_separation_order_names is only set if
1054
        SeparationColorNames was setup. If this was not set,
1055
        we need may need to make use of the ICCOutputColors
1056
        and page spot colors for our setup. */
1057
3.99k
        if (dev->devn_params.num_separation_order_names == 0) {
1058
            /* Page spot colors has been truncated to ensure max
1059
               colorants of the target device is not exceeded. This
1060
               is set if PDF file was encountered and should be used.
1061
               Also make sure PS file does not exceed limit of device.
1062
               However, if ICCOutputColors was specified, that should
1063
               take precedence. */
1064
3.99k
            if (dev->devn_params.page_spot_colors > 0 &&
1065
3.99k
                dev->icc_struct->spotnames == NULL)
1066
41
                xc->n_extra_channels = dev->devn_params.page_spot_colors;
1067
3.95k
            else {
1068
3.95k
                if (dev->devn_params.separations.num_separations <= (dev->color_info.max_components - NUM_CMYK_COMPONENTS))
1069
3.95k
                    xc->n_extra_channels = dev->devn_params.separations.num_separations;
1070
0
                else
1071
0
                    xc->n_extra_channels = dev->color_info.max_components - NUM_CMYK_COMPONENTS;
1072
3.95k
            }
1073
3.99k
        } else {
1074
            /* Have to figure out how many in the order list were not std
1075
               colorants */
1076
0
            spot_count = 0;
1077
0
            for (i = 0; i < dev->devn_params.num_separation_order_names; i++) {
1078
0
                if (dev->devn_params.separation_order_map[i] >= NUM_CMYK_COMPONENTS) {
1079
0
                    spot_count++;
1080
0
                }
1081
0
            }
1082
0
            xc->n_extra_channels = spot_count;
1083
0
        }
1084
3.99k
    } else {
1085
0
        xc->n_extra_channels = 0;
1086
0
    }
1087
3.99k
    xc->width = w;
1088
3.99k
    xc->height = h;
1089
    /*
1090
     * Determine the order of the output components.  This is based upon
1091
     * the SeparationOrder parameter.  This parameter can be used to select
1092
     * which planes are actually imaged.  For the process color model channels
1093
     * we image the channels which are requested.  Non requested process color
1094
     * model channels are simply filled with white.  For spot colors we only
1095
     * image the requested channels.
1096
     */
1097
20.0k
    for (i = 0; i < xc->num_channels + xc->n_extra_channels; i++) {
1098
16.0k
        xc->chnl_to_position[i] = i;
1099
16.0k
        xc->chnl_to_orig_sep[i] = i;
1100
16.0k
    }
1101
    /* If we had a specify order name, then we may need to adjust things */
1102
3.99k
    if (dev->color_info.polarity == GX_CINFO_POLARITY_SUBTRACTIVE &&
1103
3.99k
        strcmp(dev->dname, "psdcmykog") != 0) {
1104
3.99k
        if (dev->devn_params.num_separation_order_names > 0) {
1105
0
            for (i = 0; i < dev->devn_params.num_separation_order_names; i++) {
1106
0
                int sep_order_num = dev->devn_params.separation_order_map[i];
1107
0
                if (sep_order_num >= NUM_CMYK_COMPONENTS) {
1108
0
                    xc->chnl_to_position[xc->num_channels] = sep_order_num;
1109
0
                    xc->chnl_to_orig_sep[xc->num_channels++] = sep_order_num;
1110
0
                }
1111
0
            }
1112
3.99k
        } else {
1113
            /* If ICCOutputColors specified then just use that ordering, which
1114
               has already been set. */
1115
3.99k
            cmm_dev_profile_t *profile_struct;
1116
3.99k
            int code;
1117
1118
3.99k
            code = dev_proc(dev, get_profile)((gx_device *)dev, &profile_struct);
1119
3.99k
            if (code == 0 && profile_struct->spotnames != NULL)
1120
0
                xc->num_channels += dev->devn_params.separations.num_separations;
1121
3.99k
            else {
1122
                /* No order specified, map them alpabetically */
1123
                /* This isn't at all speed critical -- only runs once per page and */
1124
                /* there are never very many spot colors, so just search in a loop */
1125
1126
                /* If the device has tags, then that goes at the end, after all the
1127
                   spot colors */
1128
1129
3.99k
                const char *prev = " ";
1130
3.99k
                int prev_size = 1;
1131
3.99k
                psd_device *pdev_psd = (psd_device*)dev;
1132
3.99k
                bool has_tags = (pdev_psd->color_model == psd_DEVICE_CMYKT);
1133
1134
3.99k
                xc->num_channels += xc->n_extra_channels;
1135
4.06k
                for (i=xc->base_num_channels + has_tags; i < xc->num_channels; i++) {
1136
68
                    int j;
1137
68
                    const char *curr = "\377";
1138
68
                    int curr_size = 1;
1139
68
                    bool compare;
1140
1141
224
                    for (j=xc->base_num_channels + has_tags; j < xc->num_channels; j++) {
1142
156
                        devn_separation_name *separation_name;
1143
1144
156
                        separation_name = &(dev->devn_params.separations.names[j - xc->base_num_channels]);
1145
156
                        compare = strncmp((const char*) separation_name->data, curr, min(curr_size, separation_name->size));
1146
156
                        if (compare < 0 || (compare == 0 && separation_name->size < curr_size)) {
1147
154
                            compare = strncmp((const char*) separation_name->data, prev, min(prev_size, separation_name->size));
1148
154
                            if (compare > 0 || (compare == 0 && separation_name->size > prev_size)) {
1149
45
                                xc->chnl_to_position[i] = j;
1150
45
                                xc->chnl_to_orig_sep[i] = j;
1151
45
                                curr = (const char*) separation_name->data;
1152
45
                                curr_size = separation_name->size;
1153
45
                            }
1154
154
                        }
1155
156
                    }
1156
68
                    prev = curr;    /* next color has to sort after this one */
1157
68
                    prev_size = curr_size;
1158
68
                }
1159
3.99k
            }
1160
3.99k
        }
1161
3.99k
    }
1162
3.99k
    return 0;
1163
3.99k
}
1164
1165
int
1166
160k
psd_write(psd_write_ctx *xc, const byte *buf, int size) {
1167
160k
    int code;
1168
1169
160k
    code = gp_fwrite(buf, 1, size, xc->f);
1170
160k
    if (code < 0)
1171
0
        return code;
1172
160k
    return 0;
1173
160k
}
1174
1175
int
1176
psd_write_8(psd_write_ctx *xc, byte v)
1177
231
{
1178
231
    return psd_write(xc, (byte *)&v, 1);
1179
231
}
1180
1181
int
1182
psd_write_16(psd_write_ctx *xc, bits16 v)
1183
72.3k
{
1184
72.3k
    bits16 buf;
1185
1186
72.3k
    assign_u16(buf, v);
1187
72.3k
    return psd_write(xc, (byte *)&buf, 2);
1188
72.3k
}
1189
1190
int
1191
psd_write_32(psd_write_ctx *xc, bits32 v)
1192
47.9k
{
1193
47.9k
    bits32 buf;
1194
1195
47.9k
    assign_u32(buf, v);
1196
47.9k
    return psd_write(xc, (byte *)&buf, 4);
1197
47.9k
}
1198
1199
static fixed_colorant_name
1200
get_sep_name(gx_devn_prn_device *pdev, int n)
1201
35
{
1202
35
    fixed_colorant_name p = NULL;
1203
35
    int i;
1204
1205
175
    for (i = 0; i <= n; i++) {
1206
175
        p = pdev->devn_params.std_colorant_names[i];
1207
175
        if (p == NULL)
1208
35
            break;
1209
175
    }
1210
35
    return p;
1211
35
}
1212
1213
static inline void
1214
psd_write_src_spot_names(psd_write_ctx *xc, gx_devn_prn_device *pdev, int chan_idx, bool has_tags)
1215
3.99k
{
1216
3.99k
    int sep_num;
1217
3.99k
    const devn_separation_name *separation_name;
1218
1219
4.06k
    for (; chan_idx < xc->num_channels; chan_idx++) {
1220
68
        sep_num = xc->chnl_to_orig_sep[chan_idx] - NUM_CMYK_COMPONENTS - has_tags;
1221
68
        separation_name = &(pdev->devn_params.separations.names[sep_num]);
1222
68
        psd_write_8(xc, (byte)separation_name->size);
1223
68
        psd_write(xc, separation_name->data, separation_name->size);
1224
68
    }
1225
3.99k
}
1226
1227
static inline void
1228
psd_write_std_extra_names(psd_write_ctx *xc, gx_devn_prn_device *pdev, int chan_idx)
1229
3.99k
{
1230
3.99k
    for (; chan_idx < xc->num_channels; chan_idx++) {
1231
41
        int len;
1232
41
        fixed_colorant_name n = pdev->devn_params.std_colorant_names[chan_idx];
1233
41
        if (n == NULL)
1234
41
            break;
1235
0
        len = strlen(n);
1236
0
        psd_write_8(xc, (byte)len);
1237
0
        psd_write(xc, (const byte*)n, len);
1238
0
    }
1239
3.99k
}
1240
1241
int
1242
psd_write_header(psd_write_ctx* xc, gx_devn_prn_device* pdev)
1243
3.99k
{
1244
3.99k
    int code = 0;
1245
3.99k
    int num_channels = xc->num_channels;
1246
3.99k
    int bpc = pdev->devn_params.bitspercomponent;
1247
3.99k
    int chan_idx;
1248
3.99k
    int chan_names_len = 0;
1249
3.99k
    int sep_num;
1250
3.99k
    const devn_separation_name *separation_name;
1251
3.99k
    cmm_dev_profile_t *profile_struct;
1252
3.99k
    cmm_profile_t *dev_profile;
1253
3.99k
    int profile_resource_size;
1254
3.99k
    psd_device *pdev_psd = (psd_device*)pdev;
1255
3.99k
    bool has_tags = (pdev_psd->color_model == psd_DEVICE_CMYKT);
1256
3.99k
    int extra_std_colors = 0;
1257
1258
3.99k
    psd_write(xc, (const byte*)"8BPS", 4); /* Signature */
1259
3.99k
    psd_write_16(xc, 1); /* Version - Always equal to 1*/
1260
    /* Reserved 6 Bytes - Must be zero */
1261
3.99k
    psd_write_32(xc, 0);
1262
3.99k
    psd_write_16(xc, 0);
1263
3.99k
    psd_write_16(xc, (bits16)num_channels); /* Channels (2 Bytes) - Supported range is 1 to 56 */
1264
3.99k
    psd_write_32(xc, xc->height); /* Rows */
1265
3.99k
    psd_write_32(xc, xc->width); /* Columns */
1266
3.99k
    psd_write_16(xc, bpc); /* Depth - 1, 8 and 16 */
1267
    /* Modes: Bitmap=0, Grayscale=1, RGB=3, CMYK=4 MultiChannel=7 Lab=9 */
1268
3.99k
    psd_write_16(xc, (bits16)xc->base_num_channels);  /* We use 1, 3 or 4. */
1269
1270
    /* Color Mode Data.  Only used for indexed and duotone */
1271
3.99k
    psd_write_32(xc, 0);
1272
1273
    /* Resources */
1274
1275
    /* ICC profile */
1276
3.99k
    code = dev_proc(pdev, get_profile)((gx_device*)pdev, &profile_struct);
1277
3.99k
    if (code < 0) {
1278
0
        dev_profile = NULL;
1279
0
        profile_resource_size = 0;
1280
3.99k
    } else {
1281
3.99k
        dev_profile = profile_struct->device_profile[GS_DEFAULT_DEVICE_PROFILE];
1282
1283
        /* Resource has to be padded to even size */
1284
3.99k
        profile_resource_size = dev_profile->buffer_size + dev_profile->buffer_size % 2;
1285
3.99k
    }
1286
1287
    /* Channel Names size computation -- this will get the "Tags" name */
1288
3.99k
    for (chan_idx = NUM_CMYK_COMPONENTS; chan_idx < xc->num_channels; chan_idx++) {
1289
41
        fixed_colorant_name n = pdev->devn_params.std_colorant_names[chan_idx];
1290
41
        if (n == NULL)
1291
41
            break;
1292
0
        chan_names_len += strlen(n) + 1;
1293
0
    }
1294
3.99k
    extra_std_colors = chan_idx - NUM_CMYK_COMPONENTS;
1295
1296
4.06k
    for (; chan_idx < xc->num_channels; chan_idx++) {
1297
68
        sep_num = xc->chnl_to_orig_sep[chan_idx] - NUM_CMYK_COMPONENTS - has_tags;
1298
68
        separation_name = &(pdev->devn_params.separations.names[sep_num]);
1299
68
        chan_names_len += (separation_name->size + 1);
1300
68
    }
1301
1302
    /* Length of resource section */
1303
3.99k
    psd_write_32(xc, 12 + (chan_names_len + (chan_names_len % 2))
1304
3.99k
                        + (12 + (14 * (xc->num_channels - xc->base_num_channels)))
1305
3.99k
                        + (profile_resource_size ? (12 + profile_resource_size) : 0) + 28);
1306
1307
    /* Channel names resource */
1308
3.99k
    psd_write(xc, (const byte *)"8BIM", 4);
1309
3.99k
    psd_write_16(xc, 1006); /* 0x03EE */
1310
3.99k
    psd_write_16(xc, 0); /* PString */
1311
3.99k
    psd_write_32(xc, chan_names_len + (chan_names_len % 2));
1312
1313
    /* If it has tags, do the spots first (if there are any),
1314
       then the tags. We will need to rework this if we were
1315
       to add tags to psdcmykog or similar such device that
1316
       has pre-defined spots with the tags plane */
1317
3.99k
    if (has_tags) {
1318
0
        chan_idx = NUM_CMYK_COMPONENTS + extra_std_colors;
1319
0
        psd_write_src_spot_names(xc, pdev, chan_idx, has_tags);
1320
0
        chan_idx = NUM_CMYK_COMPONENTS;
1321
0
        psd_write_std_extra_names(xc, pdev, chan_idx);
1322
1323
3.99k
    } else {
1324
3.99k
        chan_idx = NUM_CMYK_COMPONENTS;
1325
3.99k
        psd_write_std_extra_names(xc, pdev, chan_idx);
1326
3.99k
        chan_idx = NUM_CMYK_COMPONENTS + extra_std_colors;
1327
3.99k
        psd_write_src_spot_names(xc, pdev, chan_idx, has_tags);
1328
3.99k
    }
1329
3.99k
    if (chan_names_len % 2)
1330
27
        psd_write_8(xc, 0); /* pad */
1331
1332
    /* DisplayInfo - Colors for each spot channels resource*/
1333
3.99k
    psd_write(xc, (const byte *)"8BIM", 4);
1334
3.99k
    psd_write_16(xc, 1007); /* 0x03EF */
1335
3.99k
    psd_write_16(xc, 0); /* PString */
1336
3.99k
    psd_write_32(xc, 14 * (xc->num_channels - xc->base_num_channels)); /* Length */
1337
4.06k
    for (chan_idx = NUM_CMYK_COMPONENTS; chan_idx < xc->num_channels; chan_idx++) {
1338
68
        sep_num = xc->chnl_to_orig_sep[chan_idx] - NUM_CMYK_COMPONENTS;
1339
68
        psd_write_16(xc, 02); /* CMYK */
1340
        /* PhotoShop stores all component values as if they were additive. */
1341
68
        if (pdev->equiv_cmyk_colors.color[sep_num].color_info_valid) {
1342
132
#define convert_color(component) ((bits16)((65535 * ((double)\
1343
132
    (frac_1 - pdev->equiv_cmyk_colors.color[sep_num].component)) / frac_1)))
1344
33
            psd_write_16(xc, convert_color(c)); /* Cyan */
1345
33
            psd_write_16(xc, convert_color(m)); /* Magenta */
1346
33
            psd_write_16(xc, convert_color(y)); /* Yellow */
1347
33
            psd_write_16(xc, convert_color(k)); /* Black */
1348
33
#undef convert_color
1349
35
        } else {
1350
            /* This is a bit of a hack, introduced for the psdcmykog device
1351
             * so that we get a reasonable approximation for the colors out
1352
             * even when used without the appropriate profile. */
1353
35
            fixed_colorant_name sepname = get_sep_name(pdev, chan_idx);
1354
35
            if (sepname && !strcmp(sepname, "Artifex Orange")) {
1355
0
                psd_write_16(xc, 0xfbde); /* Cyan */
1356
0
                psd_write_16(xc, 0x7376); /* Magenta */
1357
0
                psd_write_16(xc, 0x0000); /* Yellow */
1358
0
                psd_write_16(xc, 0xffff); /* Black */
1359
35
            } else if (sepname && !strcmp(sepname, "Artifex Green")) {
1360
0
                psd_write_16(xc, 0x0000); /* Cyan */
1361
0
                psd_write_16(xc, 0xe33d); /* Magenta */
1362
0
                psd_write_16(xc, 0x0000); /* Yellow */
1363
0
                psd_write_16(xc, 0xf8c8); /* Black */
1364
35
            } else {
1365
                /* Else set C = M = Y = 0, K = 1 */
1366
35
                psd_write_16(xc, 65535); /* Cyan */
1367
35
                psd_write_16(xc, 65535); /* Magenta */
1368
35
                psd_write_16(xc, 65535); /* Yellow */
1369
35
                psd_write_16(xc, 0); /* Black */
1370
35
            }
1371
35
        }
1372
68
        psd_write_16(xc, 0); /* Opacity 0 to 100 */
1373
68
        psd_write_8(xc, 2); /* Don't know */
1374
68
        psd_write_8(xc, 0); /* Padding - Always Zero */
1375
68
    }
1376
1377
    /* Image resolution resource */
1378
3.99k
    psd_write(xc, (const byte *)"8BIM", 4);
1379
3.99k
    psd_write_16(xc, 1005); /* 0x03ED */
1380
3.99k
    psd_write_16(xc, 0); /* PString */
1381
3.99k
    psd_write_32(xc, 16); /* Length */
1382
                /* Resolution is specified as a fixed 16.16 bits */
1383
3.99k
    psd_write_32(xc, (int) (pdev->HWResolution[0] * 0x10000 * xc->width / pdev->width + 0.5));
1384
3.99k
    psd_write_16(xc, 1);  /* width:  1 --> resolution is pixels per inch */
1385
3.99k
    psd_write_16(xc, 1);  /* width:  1 --> resolution is pixels per inch */
1386
3.99k
    psd_write_32(xc, (int) (pdev->HWResolution[1] * 0x10000 * xc->height / pdev->height + 0.5));
1387
3.99k
    psd_write_16(xc, 1);  /* height:  1 --> resolution is pixels per inch */
1388
3.99k
    psd_write_16(xc, 1);  /* height:  1 --> resolution is pixels per inch */
1389
1390
    /* ICC Profile resource */
1391
3.99k
    if (profile_resource_size) {
1392
3.99k
        psd_write(xc, (const byte*)"8BIM", 4);
1393
3.99k
        psd_write_16(xc, 1039); /* 0x040F */
1394
3.99k
        psd_write_16(xc, 0);    /* PString */
1395
3.99k
        psd_write_32(xc, profile_resource_size);
1396
3.99k
        psd_write(xc, dev_profile->buffer, dev_profile->buffer_size);
1397
3.99k
        if (dev_profile->buffer_size % 2)
1398
0
            psd_write_8(xc, 0);
1399
3.99k
    }
1400
1401
    /* Layer and Mask information */
1402
3.99k
    psd_write_32(xc, 0);  /* No layer or mask information */
1403
1404
    /* Compression: 0=None, 1=RLE/PackBits, 2=Deflate 3=Defalte+Prediction */
1405
3.99k
    psd_write_16(xc, 0);
1406
1407
3.99k
    return code;
1408
3.99k
}
1409
1410
/*
1411
 * Close device and clean up ICC structures.
1412
 */
1413
static int
1414
psd_prn_close(gx_device *dev)
1415
13.5k
{
1416
13.5k
    psd_device * const xdev = (psd_device *) dev;
1417
1418
13.5k
    if (xdev->cmyk_icc_link != NULL) {
1419
0
        gscms_release_link(xdev->cmyk_icc_link);
1420
0
        rc_decrement(xdev->cmyk_profile, "psd_prn_close");
1421
0
    }
1422
1423
13.5k
    if (xdev->rgb_icc_link != NULL) {
1424
0
        gscms_release_link(xdev->rgb_icc_link);
1425
0
        rc_decrement(xdev->rgb_profile, "psd_prn_close");
1426
0
    }
1427
1428
13.5k
    if (xdev->output_icc_link != NULL) {
1429
0
        gscms_release_link(xdev->output_icc_link);
1430
0
        rc_decrement(xdev->output_profile, "psd_prn_close");
1431
0
    }
1432
1433
13.5k
    return gdev_prn_close(dev);
1434
13.5k
}
1435
1436
/*
1437
 * Output the image data for the PSD device.  The data for the PSD is
1438
 * written in separate planes.  If the device is psdrgb then we simply
1439
 * write three planes of RGB data.  The DeviceN parameters (SeparationOrder,
1440
 * SeparationCOlorNames, and MaxSeparations) are not applied to the psdrgb
1441
 * device.
1442
 *
1443
 * The DeviceN parameters are applied to the psdcmyk device.  If the
1444
 * SeparationOrder parameter is not specified then first we write out the data
1445
 * for the CMYK planes and then any separation planes.  If the SeparationOrder
1446
 * parameter is specified, then things are more complicated.  Logically we
1447
 * would simply write the planes specified by the SeparationOrder data.
1448
 * However Photoshop expects there to be CMYK data.  First we will write out
1449
 * four planes of data for CMYK.  If any of these colors are present in the
1450
 * SeparationOrder data then the plane data will contain the color information.
1451
 * If a color is not present then the plane data will be zero.  After the CMYK
1452
 * data, we will write out any separation data which is specified in the
1453
 * SeparationOrder data.
1454
 */
1455
1456
static int
1457
psd_write_image_data(psd_write_ctx *xc, gx_device_printer *pdev)
1458
3.99k
{
1459
1460
3.99k
    psd_device *psd_dev = (psd_device *)pdev;
1461
3.99k
    int bpc = psd_dev->devn_params.bitspercomponent;
1462
3.99k
    int raster_plane = bitmap_raster(pdev->width * bpc);
1463
3.99k
    byte *planes[GS_CLIENT_COLOR_MAX_COMPONENTS];
1464
3.99k
    int code = 0;
1465
3.99k
    int i, j;
1466
3.99k
    byte *sep_line;
1467
3.99k
    int base_num_channels = xc->base_num_channels;
1468
3.99k
    int chan_idx;
1469
3.99k
    byte * unpacked;
1470
3.99k
    int num_comp = xc->num_channels;
1471
3.99k
    gs_get_bits_params_t params;
1472
3.99k
    gx_downscaler_t ds = { NULL };
1473
3.99k
    int octets_per_component = bpc >> 3;
1474
3.99k
    int octets_per_line = xc->width * octets_per_component;
1475
1476
    /* Return planar data */
1477
3.99k
    params.options = (GB_RETURN_POINTER | GB_RETURN_COPY |
1478
3.99k
         GB_ALIGN_STANDARD | GB_OFFSET_0 | GB_RASTER_STANDARD |
1479
3.99k
         GB_PACKING_PLANAR | GB_COLORS_NATIVE | GB_ALPHA_NONE);
1480
3.99k
    params.x_offset = 0;
1481
3.99k
    params.raster = bitmap_raster(pdev->width * pdev->color_info.depth);
1482
1483
3.99k
    sep_line = gs_alloc_bytes(pdev->memory, octets_per_line, "psd_write_sep_line");
1484
1485
20.0k
    for (chan_idx = 0; chan_idx < num_comp; chan_idx++) {
1486
16.0k
        planes[chan_idx] = gs_alloc_bytes(pdev->memory, raster_plane,
1487
16.0k
                                        "psd_write_sep_line");
1488
16.0k
        params.data[chan_idx] = planes[chan_idx];
1489
16.0k
        if (params.data[chan_idx] == NULL)
1490
0
            return_error(gs_error_VMerror);
1491
16.0k
    }
1492
1493
3.99k
    if (sep_line == NULL)
1494
0
        return_error(gs_error_VMerror);
1495
1496
3.99k
    code = gx_downscaler_init_planar(&ds, (gx_device *)pdev,
1497
3.99k
                                     bpc, bpc, num_comp,
1498
3.99k
                                     &psd_dev->downscale,
1499
3.99k
                                     &params);
1500
3.99k
    if (code < 0)
1501
0
        goto cleanup;
1502
1503
    /* Print the output planes */
1504
3.99k
    for (j = 0; j < xc->height; ++j) {
1505
3.99k
        code = gx_downscaler_get_bits_rectangle(&ds, &params, j);
1506
3.99k
        if (code < 0)
1507
0
            goto cleanup;
1508
20.0k
        for (chan_idx = 0; chan_idx < num_comp; chan_idx++) {
1509
16.0k
            int data_pos = xc->chnl_to_position[chan_idx];
1510
16.0k
            if (data_pos >= 0) {
1511
1512
16.0k
                unpacked = params.data[data_pos];
1513
1514
16.0k
                if (base_num_channels == 3) {
1515
0
                    memcpy(sep_line, unpacked, octets_per_line);
1516
16.0k
                } else if (octets_per_component == 1) {
1517
24.4M
                    for (i = 0; i < xc->width; ++i) {
1518
24.4M
                        sep_line[i] = 255 - unpacked[i];
1519
24.4M
                    }
1520
16.0k
                } else { /* octets_per_component == 2 */
1521
0
                    for (i = 0; i < xc->width; ++i) {
1522
0
                        ((unsigned short *)sep_line)[i] = 65535 - ((unsigned short *)unpacked)[i];
1523
0
                    }
1524
0
                }
1525
16.0k
                psd_write(xc, sep_line, octets_per_line);
1526
16.0k
            } else if (chan_idx < NUM_CMYK_COMPONENTS) {
1527
                /* Write empty process color in the area */
1528
0
                memset(sep_line,255,octets_per_line);
1529
0
                psd_write(xc, sep_line, octets_per_line);
1530
0
            }
1531
16.0k
            code = gp_fseek(xc->f, ((gs_offset_t)xc->height-1) * octets_per_line, SEEK_CUR);
1532
16.0k
            if (code < 0) {
1533
0
                code = gs_note_error(gs_error_ioerror);
1534
0
                goto cleanup;
1535
0
            }
1536
16.0k
        }
1537
3.99k
        if (j < xc->height-1) {
1538
3.99k
            code = gp_fseek(xc->f, -((gs_offset_t)num_comp * xc->height - 1) * octets_per_line, SEEK_CUR);
1539
3.99k
            if (code < 0) {
1540
3.99k
                code = gs_note_error(gs_error_ioerror);
1541
3.99k
                goto cleanup;
1542
3.99k
            }
1543
3.99k
        }
1544
3.99k
    }
1545
1546
3.99k
cleanup:
1547
3.99k
    gx_downscaler_fin(&ds);
1548
3.99k
    gs_free_object(pdev->memory, sep_line, "psd_write_sep_line");
1549
20.0k
    for (chan_idx = 0; chan_idx < num_comp; chan_idx++) {
1550
16.0k
        gs_free_object(pdev->memory, planes[chan_idx],
1551
16.0k
                                        "psd_write_image_data");
1552
16.0k
    }
1553
3.99k
    return code;
1554
3.99k
}
1555
1556
bool
1557
psd_allow_multiple_pages (gx_device_printer *pdev)
1558
3.99k
{
1559
3.99k
    psd_device *psd_dev = (psd_device *)pdev;
1560
3.99k
    int code;
1561
3.99k
    const char *fmt;
1562
3.99k
    bool retval = true;
1563
3.99k
    gs_parsed_file_name_t parsed;
1564
1565
3.99k
    if (strcmp(gp_null_file_name, psd_dev->fname) == 0) {
1566
        /* If the output is discarded, it doesn't matter whether
1567
         * the file is format valid or not
1568
         */
1569
3.99k
        retval = true;
1570
3.99k
    }
1571
0
    else {
1572
0
        code = gx_parse_output_file_name(&parsed, &fmt, psd_dev->fname,
1573
0
                                     strlen(psd_dev->fname), psd_dev->memory);
1574
0
        if (code < 0 || (fmt == NULL && psd_dev->PageCount > 0)) {
1575
0
            retval = false;
1576
0
        }
1577
0
    }
1578
3.99k
    return retval;
1579
3.99k
}
1580
1581
static int
1582
psd_print_page(gx_device_printer *pdev, gp_file *file)
1583
3.99k
{
1584
3.99k
    psd_write_ctx xc;
1585
3.99k
    gx_devn_prn_device *devn_dev = (gx_devn_prn_device *)pdev;
1586
3.99k
    psd_device *psd_dev = (psd_device *)pdev;
1587
3.99k
    int code = 0;
1588
1589
3.99k
    if (!psd_allow_multiple_pages(pdev)) {
1590
0
       emprintf(pdev->memory, "Use of the %%d format is required to output more than one page to PSD\nSee doc/Devices.htm#PSD for details\n\n");
1591
0
       code = gs_note_error(gs_error_ioerror);
1592
0
    }
1593
3.99k
    else {
1594
3.99k
        code = psd_setup(&xc, devn_dev, file,
1595
3.99k
                  gx_downscaler_scale(pdev->width, psd_dev->downscale.downscale_factor),
1596
3.99k
                  gx_downscaler_scale(pdev->height, psd_dev->downscale.downscale_factor));
1597
3.99k
        if (code >= 0)
1598
3.99k
            code = psd_write_header(&xc, devn_dev);
1599
3.99k
        if (code >= 0)
1600
3.99k
            code = psd_write_image_data(&xc, pdev);
1601
3.99k
    }
1602
3.99k
    return code;
1603
3.99k
}