Coverage Report

Created: 2025-11-16 07:40

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