Coverage Report

Created: 2026-04-09 07:06

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