Coverage Report

Created: 2025-08-28 07:06

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