Coverage Report

Created: 2025-06-24 07:01

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