Coverage Report

Created: 2025-06-10 06:59

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