1 /* Copyright (C) 2002 artofcode LLC. All rights reserved.
2
3 This software is provided AS-IS with no warranty, either express or
4 implied.
5
6 This software is distributed under license and may not be copied,
7 modified or distributed except as expressly authorized under the terms
8 of the license contained in the file LICENSE in this distribution.
9
10 For more information about licensing, please refer to
11 http://www.ghostscript.com/licensing/. For information on
12 commercial licensing, go to http://www.artifex.com/licensing/ or
13 contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14 San Rafael, CA 94903, U.S.A., +1(415)492-9861.
15 */
16
17 /*$Id: gdevpsd.c,v 1.23 2005/08/30 06:38:44 igor Exp $ */
18 /* PhotoShop (PSD) export device, supporting DeviceN color models. */
19
20 #include "math_.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 "icc.h"
29 #include "gxdcconv.h"
30 #include "gdevdevn.h"
31 #include "gsequivc.h"
32
33 /* Enable logic for a local ICC output profile. */
34 #define ENABLE_ICC_PROFILE 0
35
36 /* Define the device parameters. */
37 #ifndef X_DPI
38 # define X_DPI 72
39 #endif
40 #ifndef Y_DPI
41 # define Y_DPI 72
42 #endif
43
44 /* The device descriptor */
45 private dev_proc_open_device(psd_prn_open);
46 private dev_proc_get_params(psd_get_params);
47 private dev_proc_put_params(psd_put_params);
48 private dev_proc_print_page(psd_print_page);
49 private dev_proc_map_color_rgb(psd_map_color_rgb);
50 private dev_proc_get_color_mapping_procs(get_psdrgb_color_mapping_procs);
51 private dev_proc_get_color_mapping_procs(get_psd_color_mapping_procs);
52 private dev_proc_get_color_comp_index(psd_get_color_comp_index);
53 private dev_proc_encode_color(psd_encode_color);
54 private dev_proc_decode_color(psd_decode_color);
55 private dev_proc_update_spot_equivalent_colors(psd_update_spot_equivalent_colors);
56
57 /* This is redundant with color_info.cm_name. We may eliminate this
58 typedef and use the latter string for everything. */
59 typedef enum {
60 psd_DEVICE_GRAY,
61 psd_DEVICE_RGB,
62 psd_DEVICE_CMYK,
63 psd_DEVICE_N
64 } psd_color_model;
65
66 /*
67 * A structure definition for a DeviceN type device
68 */
69 typedef struct psd_device_s {
70 gx_device_common;
71 gx_prn_device_common;
72
73 /* ... device-specific parameters ... */
74
75 gs_devn_params devn_params; /* DeviceN generated parameters */
76
77 equivalent_cmyk_color_params equiv_cmyk_colors;
78
79 psd_color_model color_model;
80
81 /* ICC color profile objects, for color conversion. */
82 char profile_rgb_fn[256];
83 icmLuBase *lu_rgb;
84 int lu_rgb_outn;
85
86 char profile_cmyk_fn[256];
87 icmLuBase *lu_cmyk;
88 int lu_cmyk_outn;
89
90 char profile_out_fn[256];
91 icmLuBase *lu_out;
92 } psd_device;
93
94 /* GC procedures */
95 private
ENUM_PTRS_WITH(psd_device_enum_ptrs,psd_device * pdev)96 ENUM_PTRS_WITH(psd_device_enum_ptrs, psd_device *pdev)
97 {
98 if (index < pdev->devn_params.separations.num_separations)
99 ENUM_RETURN(pdev->devn_params.separations.names[index].data);
100 ENUM_PREFIX(st_device_printer,
101 pdev->devn_params.separations.num_separations);
102 }
103
104 ENUM_PTRS_END
RELOC_PTRS_WITH(psd_device_reloc_ptrs,psd_device * pdev)105 private RELOC_PTRS_WITH(psd_device_reloc_ptrs, psd_device *pdev)
106 {
107 RELOC_PREFIX(st_device_printer);
108 {
109 int i;
110
111 for (i = 0; i < pdev->devn_params.separations.num_separations; ++i) {
112 RELOC_PTR(psd_device, devn_params.separations.names[i].data);
113 }
114 }
115 }
116 RELOC_PTRS_END
117
118 /* Even though psd_device_finalize is the same as gx_device_finalize, */
119 /* we need to implement it separately because st_composite_final */
120 /* declares all 3 procedures as private. */
121 private void
psd_device_finalize(void * vpdev)122 psd_device_finalize(void *vpdev)
123 {
124 gx_device_finalize(vpdev);
125 }
126
127 gs_private_st_composite_final(st_psd_device, psd_device,
128 "psd_device", psd_device_enum_ptrs, psd_device_reloc_ptrs,
129 psd_device_finalize);
130
131 /*
132 * Macro definition for psd device procedures
133 */
134 #define device_procs(get_color_mapping_procs)\
135 { psd_prn_open,\
136 gx_default_get_initial_matrix,\
137 NULL, /* sync_output */\
138 gdev_prn_output_page, /* output_page */\
139 gdev_prn_close, /* close */\
140 NULL, /* map_rgb_color - not used */\
141 psd_map_color_rgb, /* map_color_rgb */\
142 NULL, /* fill_rectangle */\
143 NULL, /* tile_rectangle */\
144 NULL, /* copy_mono */\
145 NULL, /* copy_color */\
146 NULL, /* draw_line */\
147 NULL, /* get_bits */\
148 psd_get_params, /* get_params */\
149 psd_put_params, /* put_params */\
150 NULL, /* map_cmyk_color - not used */\
151 NULL, /* get_xfont_procs */\
152 NULL, /* get_xfont_device */\
153 NULL, /* map_rgb_alpha_color */\
154 gx_page_device_get_page_device, /* get_page_device */\
155 NULL, /* get_alpha_bits */\
156 NULL, /* copy_alpha */\
157 NULL, /* get_band */\
158 NULL, /* copy_rop */\
159 NULL, /* fill_path */\
160 NULL, /* stroke_path */\
161 NULL, /* fill_mask */\
162 NULL, /* fill_trapezoid */\
163 NULL, /* fill_parallelogram */\
164 NULL, /* fill_triangle */\
165 NULL, /* draw_thin_line */\
166 NULL, /* begin_image */\
167 NULL, /* image_data */\
168 NULL, /* end_image */\
169 NULL, /* strip_tile_rectangle */\
170 NULL, /* strip_copy_rop */\
171 NULL, /* get_clipping_box */\
172 NULL, /* begin_typed_image */\
173 NULL, /* get_bits_rectangle */\
174 NULL, /* map_color_rgb_alpha */\
175 NULL, /* create_compositor */\
176 NULL, /* get_hardware_params */\
177 NULL, /* text_begin */\
178 NULL, /* finish_copydevice */\
179 NULL, /* begin_transparency_group */\
180 NULL, /* end_transparency_group */\
181 NULL, /* begin_transparency_mask */\
182 NULL, /* end_transparency_mask */\
183 NULL, /* discard_transparency_layer */\
184 get_color_mapping_procs, /* get_color_mapping_procs */\
185 psd_get_color_comp_index, /* get_color_comp_index */\
186 psd_encode_color, /* encode_color */\
187 psd_decode_color, /* decode_color */\
188 NULL, /* pattern_manage */\
189 NULL, /* fill_rectangle_hl_color */\
190 NULL, /* include_color_space */\
191 NULL, /* fill_linear_color_scanline */\
192 NULL, /* fill_linear_color_trapezoid */\
193 NULL, /* fill_linear_color_triangle */\
194 psd_update_spot_equivalent_colors /* update_spot_equivalent_colors */\
195 }
196
197
198 private fixed_colorant_name DeviceGrayComponents[] = {
199 "Gray",
200 0 /* List terminator */
201 };
202
203 private fixed_colorant_name DeviceRGBComponents[] = {
204 "Red",
205 "Green",
206 "Blue",
207 0 /* List terminator */
208 };
209
210 #define psd_device_body(procs, dname, ncomp, pol, depth, mg, mc, cn)\
211 std_device_full_body_type_extended(psd_device, &procs, dname,\
212 &st_psd_device,\
213 (int)((long)(DEFAULT_WIDTH_10THS) * (X_DPI) / 10),\
214 (int)((long)(DEFAULT_HEIGHT_10THS) * (Y_DPI) / 10),\
215 X_DPI, Y_DPI,\
216 GX_DEVICE_COLOR_MAX_COMPONENTS, /* MaxComponents */\
217 ncomp, /* NumComp */\
218 pol, /* Polarity */\
219 depth, 0, /* Depth, GrayIndex */\
220 mg, mc, /* MaxGray, MaxColor */\
221 mg + 1, mc + 1, /* DitherGray, DitherColor */\
222 GX_CINFO_SEP_LIN, /* Linear & Separable */\
223 cn, /* Process color model name */\
224 0, 0, /* offsets */\
225 0, 0, 0, 0 /* margins */\
226 ),\
227 prn_device_body_rest_(psd_print_page)
228
229 /*
230 * PSD device with RGB process color model.
231 */
232 private const gx_device_procs spot_rgb_procs = device_procs(get_psdrgb_color_mapping_procs);
233
234 const psd_device gs_psdrgb_device =
235 {
236 psd_device_body(spot_rgb_procs, "psdrgb", 3, GX_CINFO_POLARITY_ADDITIVE, 24, 255, 255, "DeviceRGB"),
237 /* devn_params specific parameters */
238 { 8, /* Bits per color - must match ncomp, depth, etc. above */
239 DeviceRGBComponents, /* Names of color model colorants */
240 3, /* Number colorants for RGB */
241 0, /* MaxSeparations has not been specified */
242 {0}, /* SeparationNames */
243 0, /* SeparationOrder names */
244 {0, 1, 2, 3, 4, 5, 6, 7 } /* Initial component SeparationOrder */
245 },
246 { true }, /* equivalent CMYK colors for spot colors */
247 /* PSD device specific parameters */
248 psd_DEVICE_RGB, /* Color model */
249 };
250
251 /*
252 * Select the default number of components based upon the number of bits
253 * that we have in a gx_color_index
254 */
255 #define NC ((arch_sizeof_color_index <= 8) ? arch_sizeof_color_index : 8)
256
257 /*
258 * PSD device with CMYK process color model and spot color support.
259 */
260 private const gx_device_procs spot_cmyk_procs
261 = device_procs(get_psd_color_mapping_procs);
262
263 const psd_device gs_psdcmyk_device =
264 {
265 psd_device_body(spot_cmyk_procs, "psdcmyk", NC, GX_CINFO_POLARITY_SUBTRACTIVE, NC * 8, 255, 255, "DeviceCMYK"),
266 /* devn_params specific parameters */
267 { 8, /* Bits per color - must match ncomp, depth, etc. above */
268 DeviceCMYKComponents, /* Names of color model colorants */
269 4, /* Number colorants for CMYK */
270 NC, /* MaxSeparations has not been specified */
271 {0}, /* SeparationNames */
272 0, /* SeparationOrder names */
273 {0, 1, 2, 3, 4, 5, 6, 7 } /* Initial component SeparationOrder */
274 },
275 { true }, /* equivalent CMYK colors for spot colors */
276 /* PSD device specific parameters */
277 psd_DEVICE_CMYK, /* Color model */
278 };
279
280 #undef NC
281
282 /* Open the psd devices */
283 int
psd_prn_open(gx_device * pdev)284 psd_prn_open(gx_device * pdev)
285 {
286 int code = gdev_prn_open(pdev);
287
288 set_linear_color_bits_mask_shift(pdev);
289 pdev->color_info.separable_and_linear = GX_CINFO_SEP_LIN;
290 return code;
291 }
292
293 /*
294 * The following procedures are used to map the standard color spaces into
295 * the color components for the psdrgb device.
296 */
297 private void
gray_cs_to_psdrgb_cm(gx_device * dev,frac gray,frac out[])298 gray_cs_to_psdrgb_cm(gx_device * dev, frac gray, frac out[])
299 {
300 int i = ((psd_device *)dev)->devn_params.separations.num_separations;
301
302 out[0] = out[1] = out[2] = gray;
303 for(; i>0; i--) /* Clear spot colors */
304 out[2 + i] = 0;
305 }
306
307 private void
rgb_cs_to_psdrgb_cm(gx_device * dev,const gs_imager_state * pis,frac r,frac g,frac b,frac out[])308 rgb_cs_to_psdrgb_cm(gx_device * dev, const gs_imager_state *pis,
309 frac r, frac g, frac b, frac out[])
310 {
311 int i = ((psd_device *)dev)->devn_params.separations.num_separations;
312
313 out[0] = r;
314 out[1] = g;
315 out[2] = b;
316 for(; i>0; i--) /* Clear spot colors */
317 out[2 + i] = 0;
318 }
319
320 private void
cmyk_cs_to_psdrgb_cm(gx_device * dev,frac c,frac m,frac y,frac k,frac out[])321 cmyk_cs_to_psdrgb_cm(gx_device * dev,
322 frac c, frac m, frac y, frac k, frac out[])
323 {
324 int i = ((psd_device *)dev)->devn_params.separations.num_separations;
325
326 color_cmyk_to_rgb(c, m, y, k, NULL, out);
327 for(; i>0; i--) /* Clear spot colors */
328 out[2 + i] = 0;
329 }
330
331 /* Color mapping routines for the psdcmyk device */
332
333 private void
gray_cs_to_psdcmyk_cm(gx_device * dev,frac gray,frac out[])334 gray_cs_to_psdcmyk_cm(gx_device * dev, frac gray, frac out[])
335 {
336 int * map = ((psd_device *) dev)->devn_params.separation_order_map;
337
338 gray_cs_to_devn_cm(dev, map, gray, out);
339 }
340
341 private void
rgb_cs_to_psdcmyk_cm(gx_device * dev,const gs_imager_state * pis,frac r,frac g,frac b,frac out[])342 rgb_cs_to_psdcmyk_cm(gx_device * dev, const gs_imager_state *pis,
343 frac r, frac g, frac b, frac out[])
344 {
345 int * map = ((psd_device *) dev)->devn_params.separation_order_map;
346
347 rgb_cs_to_devn_cm(dev, map, pis, r, g, b, out);
348 }
349
350 private void
cmyk_cs_to_psdcmyk_cm(gx_device * dev,frac c,frac m,frac y,frac k,frac out[])351 cmyk_cs_to_psdcmyk_cm(gx_device * dev,
352 frac c, frac m, frac y, frac k, frac out[])
353 {
354 int * map = ((psd_device *) dev)->devn_params.separation_order_map;
355
356 cmyk_cs_to_devn_cm(dev, map, c, m, y, k, out);
357 }
358
359 private void
cmyk_cs_to_spotn_cm(gx_device * dev,frac c,frac m,frac y,frac k,frac out[])360 cmyk_cs_to_spotn_cm(gx_device * dev, frac c, frac m, frac y, frac k, frac out[])
361 {
362 psd_device *xdev = (psd_device *)dev;
363 int n = xdev->devn_params.separations.num_separations;
364 icmLuBase *luo = xdev->lu_cmyk;
365 int i;
366
367 if (luo != NULL) {
368 double in[4];
369 double tmp[MAX_CHAN];
370 int outn = xdev->lu_cmyk_outn;
371
372 in[0] = frac2float(c);
373 in[1] = frac2float(m);
374 in[2] = frac2float(y);
375 in[3] = frac2float(k);
376 luo->lookup(luo, tmp, in);
377 for (i = 0; i < outn; i++)
378 out[i] = float2frac(tmp[i]);
379 for (; i < n + 4; i++)
380 out[i] = 0;
381 } else {
382 /* If no profile given, assume CMYK */
383 out[0] = c;
384 out[1] = m;
385 out[2] = y;
386 out[3] = k;
387 for(i = 0; i < n; i++) /* Clear spot colors */
388 out[4 + i] = 0;
389 }
390 }
391
392 private void
gray_cs_to_spotn_cm(gx_device * dev,frac gray,frac out[])393 gray_cs_to_spotn_cm(gx_device * dev, frac gray, frac out[])
394 {
395 cmyk_cs_to_spotn_cm(dev, 0, 0, 0, (frac)(frac_1 - gray), out);
396 }
397
398 private void
rgb_cs_to_spotn_cm(gx_device * dev,const gs_imager_state * pis,frac r,frac g,frac b,frac out[])399 rgb_cs_to_spotn_cm(gx_device * dev, const gs_imager_state *pis,
400 frac r, frac g, frac b, frac out[])
401 {
402 psd_device *xdev = (psd_device *)dev;
403 int n = xdev->devn_params.separations.num_separations;
404 icmLuBase *luo = xdev->lu_rgb;
405 int i;
406
407 if (luo != NULL) {
408 double in[3];
409 double tmp[MAX_CHAN];
410 int outn = xdev->lu_rgb_outn;
411
412 in[0] = frac2float(r);
413 in[1] = frac2float(g);
414 in[2] = frac2float(b);
415 luo->lookup(luo, tmp, in);
416 for (i = 0; i < outn; i++)
417 out[i] = float2frac(tmp[i]);
418 for (; i < n + 4; i++)
419 out[i] = 0;
420 } else {
421 frac cmyk[4];
422
423 color_rgb_to_cmyk(r, g, b, pis, cmyk);
424 cmyk_cs_to_spotn_cm(dev, cmyk[0], cmyk[1], cmyk[2], cmyk[3],
425 out);
426 }
427 }
428
429 private const gx_cm_color_map_procs psdRGB_procs = {
430 gray_cs_to_psdrgb_cm, rgb_cs_to_psdrgb_cm, cmyk_cs_to_psdrgb_cm
431 };
432
433 private const gx_cm_color_map_procs psdCMYK_procs = {
434 gray_cs_to_psdcmyk_cm, rgb_cs_to_psdcmyk_cm, cmyk_cs_to_psdcmyk_cm
435 };
436
437 private const gx_cm_color_map_procs psdN_procs = {
438 gray_cs_to_spotn_cm, rgb_cs_to_spotn_cm, cmyk_cs_to_spotn_cm
439 };
440
441 /*
442 * These are the handlers for returning the list of color space
443 * to color model conversion routines.
444 */
445 private const gx_cm_color_map_procs *
get_psdrgb_color_mapping_procs(const gx_device * dev)446 get_psdrgb_color_mapping_procs(const gx_device * dev)
447 {
448 return &psdRGB_procs;
449 }
450
451 private const gx_cm_color_map_procs *
get_psd_color_mapping_procs(const gx_device * dev)452 get_psd_color_mapping_procs(const gx_device * dev)
453 {
454 const psd_device *xdev = (const psd_device *)dev;
455
456 if (xdev->color_model == psd_DEVICE_RGB)
457 return &psdRGB_procs;
458 else if (xdev->color_model == psd_DEVICE_CMYK)
459 return &psdCMYK_procs;
460 else if (xdev->color_model == psd_DEVICE_N)
461 return &psdN_procs;
462 else
463 return NULL;
464 }
465
466 /*
467 * Encode a list of colorant values into a gx_color_index_value.
468 */
469 private gx_color_index
psd_encode_color(gx_device * dev,const gx_color_value colors[])470 psd_encode_color(gx_device *dev, const gx_color_value colors[])
471 {
472 int bpc = ((psd_device *)dev)->devn_params.bitspercomponent;
473 int drop = sizeof(gx_color_value) * 8 - bpc;
474 gx_color_index color = 0;
475 int i = 0;
476 int ncomp = dev->color_info.num_components;
477
478 for (; i<ncomp; i++) {
479 color <<= bpc;
480 color |= (colors[i] >> drop);
481 }
482 return (color == gx_no_color_index ? color ^ 1 : color);
483 }
484
485 /*
486 * Decode a gx_color_index value back to a list of colorant values.
487 */
488 private int
psd_decode_color(gx_device * dev,gx_color_index color,gx_color_value * out)489 psd_decode_color(gx_device * dev, gx_color_index color, gx_color_value * out)
490 {
491 int bpc = ((psd_device *)dev)->devn_params.bitspercomponent;
492 int drop = sizeof(gx_color_value) * 8 - bpc;
493 int mask = (1 << bpc) - 1;
494 int i = 0;
495 int ncomp = dev->color_info.num_components;
496
497 for (; i<ncomp; i++) {
498 out[ncomp - i - 1] = (gx_color_value) ((color & mask) << drop);
499 color >>= bpc;
500 }
501 return 0;
502 }
503
504 /*
505 * Convert a gx_color_index to RGB.
506 */
507 private int
psd_map_color_rgb(gx_device * dev,gx_color_index color,gx_color_value rgb[3])508 psd_map_color_rgb(gx_device *dev, gx_color_index color, gx_color_value rgb[3])
509 {
510 psd_device *xdev = (psd_device *)dev;
511
512 if (xdev->color_model == psd_DEVICE_RGB)
513 return psd_decode_color(dev, color, rgb);
514 /* TODO: return reasonable values. */
515 rgb[0] = 0;
516 rgb[1] = 0;
517 rgb[2] = 0;
518 return 0;
519 }
520
521 /*
522 * Device proc for updating the equivalent CMYK color for spot colors.
523 */
524 private int
psd_update_spot_equivalent_colors(gx_device * pdev,const gs_state * pgs)525 psd_update_spot_equivalent_colors(gx_device *pdev, const gs_state * pgs)
526 {
527 psd_device * psdev = (psd_device *)pdev;
528
529 update_spot_equivalent_cmyk_colors(pdev, pgs,
530 &psdev->devn_params, &psdev->equiv_cmyk_colors);
531 return 0;
532 }
533
534 #if ENABLE_ICC_PROFILE
535 private int
psd_open_profile(psd_device * xdev,char * profile_fn,icmLuBase ** pluo,int * poutn)536 psd_open_profile(psd_device *xdev, char *profile_fn, icmLuBase **pluo,
537 int *poutn)
538 {
539 icmFile *fp;
540 icc *icco;
541 icmLuBase *luo;
542
543 dlprintf1("psd_open_profile %s\n", profile_fn);
544 fp = new_icmFileStd_name(profile_fn, (char *)"rb");
545 if (fp == NULL)
546 return_error(gs_error_undefinedfilename);
547 icco = new_icc();
548 if (icco == NULL)
549 return_error(gs_error_VMerror);
550 if (icco->read(icco, fp, 0))
551 return_error(gs_error_rangecheck);
552 luo = icco->get_luobj(icco, icmFwd, icmDefaultIntent, icmSigDefaultData, icmLuOrdNorm);
553 if (luo == NULL)
554 return_error(gs_error_rangecheck);
555 *pluo = luo;
556 luo->spaces(luo, NULL, NULL, NULL, poutn, NULL, NULL, NULL, NULL);
557 return 0;
558 }
559
560 private int
psd_open_profiles(psd_device * xdev)561 psd_open_profiles(psd_device *xdev)
562 {
563 int code = 0;
564 if (xdev->lu_out == NULL && xdev->profile_out_fn[0]) {
565 code = psd_open_profile(xdev, xdev->profile_out_fn,
566 &xdev->lu_out, NULL);
567 }
568 if (code >= 0 && xdev->lu_rgb == NULL && xdev->profile_rgb_fn[0]) {
569 code = psd_open_profile(xdev, xdev->profile_rgb_fn,
570 &xdev->lu_rgb, &xdev->lu_rgb_outn);
571 }
572 if (code >= 0 && xdev->lu_cmyk == NULL && xdev->profile_cmyk_fn[0]) {
573 code = psd_open_profile(xdev, xdev->profile_cmyk_fn,
574 &xdev->lu_cmyk, &xdev->lu_cmyk_outn);
575 }
576 return code;
577 }
578 #endif
579
580 /* Get parameters. We provide a default CRD. */
581 private int
psd_get_params(gx_device * pdev,gs_param_list * plist)582 psd_get_params(gx_device * pdev, gs_param_list * plist)
583 {
584 psd_device *xdev = (psd_device *)pdev;
585 int code;
586 #if ENABLE_ICC_PROFILE
587 gs_param_string pos;
588 gs_param_string prgbs;
589 gs_param_string pcmyks;
590 #endif
591
592 code = gdev_prn_get_params(pdev, plist);
593 if (code < 0)
594 return code;
595 code = devn_get_params(pdev, plist,
596 &(xdev->devn_params), &(xdev->equiv_cmyk_colors));
597 if (code < 0)
598 return code;
599
600 #if ENABLE_ICC_PROFILE
601 pos.data = (const byte *)xdev->profile_out_fn,
602 pos.size = strlen(xdev->profile_out_fn),
603 pos.persistent = false;
604 code = param_write_string(plist, "ProfileOut", &pos);
605 if (code < 0)
606 return code;
607
608 prgbs.data = (const byte *)xdev->profile_rgb_fn,
609 prgbs.size = strlen(xdev->profile_rgb_fn),
610 prgbs.persistent = false;
611 code = param_write_string(plist, "ProfileRgb", &prgbs);
612 if (code < 0)
613 return code;
614
615 pcmyks.data = (const byte *)xdev->profile_cmyk_fn,
616 pcmyks.size = strlen(xdev->profile_cmyk_fn),
617 pcmyks.persistent = false;
618 code = param_write_string(plist, "ProfileCmyk", &prgbs);
619 #endif
620
621 return code;
622 }
623
624 #if ENABLE_ICC_PROFILE
625 private int
psd_param_read_fn(gs_param_list * plist,const char * name,gs_param_string * pstr,uint max_len)626 psd_param_read_fn(gs_param_list *plist, const char *name,
627 gs_param_string *pstr, uint max_len)
628 {
629 int code = param_read_string(plist, name, pstr);
630
631 if (code == 0) {
632 if (pstr->size >= max_len)
633 param_signal_error(plist, name, code = gs_error_rangecheck);
634 } else {
635 pstr->data = 0;
636 }
637 return code;
638 }
639 #endif
640
641 /* Compare a C string and a gs_param_string. */
642 static bool
param_string_eq(const gs_param_string * pcs,const char * str)643 param_string_eq(const gs_param_string *pcs, const char *str)
644 {
645 return (strlen(str) == pcs->size &&
646 !strncmp(str, (const char *)pcs->data, pcs->size));
647 }
648
649 private int
psd_set_color_model(psd_device * xdev,psd_color_model color_model)650 psd_set_color_model(psd_device *xdev, psd_color_model color_model)
651 {
652 xdev->color_model = color_model;
653 if (color_model == psd_DEVICE_GRAY) {
654 xdev->devn_params.std_colorant_names = DeviceGrayComponents;
655 xdev->devn_params.num_std_colorant_names = 1;
656 xdev->color_info.cm_name = "DeviceGray";
657 xdev->color_info.polarity = GX_CINFO_POLARITY_ADDITIVE;
658 } else if (color_model == psd_DEVICE_RGB) {
659 xdev->devn_params.std_colorant_names = DeviceRGBComponents;
660 xdev->devn_params.num_std_colorant_names = 3;
661 xdev->color_info.cm_name = "DeviceRGB";
662 xdev->color_info.polarity = GX_CINFO_POLARITY_ADDITIVE;
663 } else if (color_model == psd_DEVICE_CMYK) {
664 xdev->devn_params.std_colorant_names = DeviceCMYKComponents;
665 xdev->devn_params.num_std_colorant_names = 4;
666 xdev->color_info.cm_name = "DeviceCMYK";
667 xdev->color_info.polarity = GX_CINFO_POLARITY_SUBTRACTIVE;
668 } else if (color_model == psd_DEVICE_N) {
669 xdev->devn_params.std_colorant_names = DeviceCMYKComponents;
670 xdev->devn_params.num_std_colorant_names = 4;
671 xdev->color_info.cm_name = "DeviceN";
672 xdev->color_info.polarity = GX_CINFO_POLARITY_SUBTRACTIVE;
673 } else {
674 return -1;
675 }
676
677 return 0;
678 }
679
680 /* Set parameters. We allow setting the number of bits per component. */
681 private int
psd_put_params(gx_device * pdev,gs_param_list * plist)682 psd_put_params(gx_device * pdev, gs_param_list * plist)
683 {
684 psd_device * const pdevn = (psd_device *) pdev;
685 int code = 0;
686 #if ENABLE_ICC_PROFILE
687 gs_param_string po;
688 gs_param_string prgb;
689 gs_param_string pcmyk;
690 #endif
691 gs_param_string pcm;
692 psd_color_model color_model = pdevn->color_model;
693 gx_device_color_info save_info = pdevn->color_info;
694
695 #if ENABLE_ICC_PROFILE
696 code = psd_param_read_fn(plist, "ProfileOut", &po,
697 sizeof(pdevn->profile_out_fn));
698 if (code >= 0)
699 code = psd_param_read_fn(plist, "ProfileRgb", &prgb,
700 sizeof(pdevn->profile_rgb_fn));
701 if (code >= 0)
702 code = psd_param_read_fn(plist, "ProfileCmyk", &pcmyk,
703 sizeof(pdevn->profile_cmyk_fn));
704 #endif
705
706 if (code >= 0)
707 code = param_read_name(plist, "ProcessColorModel", &pcm);
708 if (code == 0) {
709 if (param_string_eq (&pcm, "DeviceGray"))
710 color_model = psd_DEVICE_GRAY;
711 else if (param_string_eq (&pcm, "DeviceRGB"))
712 color_model = psd_DEVICE_RGB;
713 else if (param_string_eq (&pcm, "DeviceCMYK"))
714 color_model = psd_DEVICE_CMYK;
715 else if (param_string_eq (&pcm, "DeviceN"))
716 color_model = psd_DEVICE_N;
717 else {
718 param_signal_error(plist, "ProcessColorModel",
719 code = gs_error_rangecheck);
720 }
721 }
722
723 if (code >= 0)
724 code = psd_set_color_model(pdevn, color_model);
725
726 /* handle the standard DeviceN related parameters */
727 if (code == 0)
728 code = devn_printer_put_params(pdev, plist,
729 &(pdevn->devn_params), &(pdevn->equiv_cmyk_colors));
730
731 if (code < 0) {
732 pdev->color_info = save_info;
733 return code;
734 }
735
736 #if ENABLE_ICC_PROFILE
737 /* Open any ICC profiles that have been specified. */
738 if (po.data != 0) {
739 memcpy(pdevn->profile_out_fn, po.data, po.size);
740 pdevn->profile_out_fn[po.size] = 0;
741 }
742 if (prgb.data != 0) {
743 memcpy(pdevn->profile_rgb_fn, prgb.data, prgb.size);
744 pdevn->profile_rgb_fn[prgb.size] = 0;
745 }
746 if (pcmyk.data != 0) {
747 memcpy(pdevn->profile_cmyk_fn, pcmyk.data, pcmyk.size);
748 pdevn->profile_cmyk_fn[pcmyk.size] = 0;
749 }
750 if (memcmp(&pdevn->color_info, &save_info,
751 size_of(gx_device_color_info)) != 0)
752 code = psd_open_profiles(pdevn);
753 #endif
754
755 return code;
756 }
757
758
759 /*
760 * This routine will check to see if the color component name match those
761 * that are available amoung the current device's color components.
762 *
763 * Parameters:
764 * dev - pointer to device data structure.
765 * pname - pointer to name (zero termination not required)
766 * nlength - length of the name
767 *
768 * This routine returns a positive value (0 to n) which is the device colorant
769 * number if the name is found. It returns a negative value if not found.
770 */
771 private int
psd_get_color_comp_index(gx_device * dev,const char * pname,int name_size,int component_type)772 psd_get_color_comp_index(gx_device * dev, const char * pname,
773 int name_size, int component_type)
774 {
775 return devn_get_color_comp_index(dev,
776 &(((psd_device *)dev)->devn_params),
777 &(((psd_device *)dev)->equiv_cmyk_colors),
778 pname, name_size, component_type, ENABLE_AUTO_SPOT_COLORS);
779 }
780
781
782 /* ------ Private definitions ------ */
783
784 /* All two-byte quantities are stored MSB-first! */
785 #if arch_is_big_endian
786 # define assign_u16(a,v) a = (v)
787 # define assign_u32(a,v) a = (v)
788 #else
789 # define assign_u16(a,v) a = ((v) >> 8) + ((v) << 8)
790 # define assign_u32(a,v) a = (((v) >> 24) & 0xff) + (((v) >> 8) & 0xff00) + (((v) & 0xff00) << 8) + (((v) & 0xff) << 24)
791 #endif
792
793 typedef struct {
794 FILE *f;
795
796 int width;
797 int height;
798 int base_bytes_pp; /* almost always 3 (rgb) or 4 (CMYK) */
799 int n_extra_channels;
800 int num_channels; /* base_bytes_pp + any spot colors that are imaged */
801 /* Map output channel number to original separation number. */
802 int chnl_to_orig_sep[GX_DEVICE_COLOR_MAX_COMPONENTS];
803 /* Map output channel number to gx_color_index position. */
804 int chnl_to_position[GX_DEVICE_COLOR_MAX_COMPONENTS];
805
806 /* byte offset of image data */
807 int image_data_off;
808 } psd_write_ctx;
809
810 private int
psd_setup(psd_write_ctx * xc,psd_device * dev)811 psd_setup(psd_write_ctx *xc, psd_device *dev)
812 {
813 int i;
814
815 #define NUM_CMYK_COMPONENTS 4
816 xc->base_bytes_pp = dev->devn_params.num_std_colorant_names;
817 xc->num_channels = xc->base_bytes_pp;
818 xc->n_extra_channels = dev->devn_params.separations.num_separations;
819 xc->width = dev->width;
820 xc->height = dev->height;
821
822 /*
823 * Determine the order of the output components. This is based upon
824 * the SeparationOrder parameter. This parameter can be used to select
825 * which planes are actually imaged. For the process color model channels
826 * we image the channels which are requested. Non requested process color
827 * model channels are simply filled with white. For spot colors we only
828 * image the requested channels. Note: There are no spot colors with
829 * the RGB color model.
830 */
831 for (i = 0; i < xc->base_bytes_pp + xc->n_extra_channels; i++)
832 xc->chnl_to_position[i] = -1;
833 for (i = 0; i < xc->base_bytes_pp + xc->n_extra_channels; i++) {
834 int sep_order_num = dev->devn_params.separation_order_map[i];
835
836 if (sep_order_num != GX_DEVICE_COLOR_MAX_COMPONENTS) {
837 if (i < NUM_CMYK_COMPONENTS) /* Do not rearrange CMYK */
838 xc->chnl_to_position[i] = sep_order_num;
839 else { /* Re arrange separations */
840 xc->chnl_to_position[xc->num_channels] = sep_order_num;
841 xc->chnl_to_orig_sep[xc->num_channels++] = i;
842 }
843 }
844 }
845
846 return 0;
847 }
848
849 private int
psd_write(psd_write_ctx * xc,const byte * buf,int size)850 psd_write(psd_write_ctx *xc, const byte *buf, int size) {
851 int code;
852
853 code = fwrite(buf, 1, size, xc->f);
854 if (code < 0)
855 return code;
856 return 0;
857 }
858
859 private int
psd_write_8(psd_write_ctx * xc,byte v)860 psd_write_8(psd_write_ctx *xc, byte v)
861 {
862 return psd_write(xc, (byte *)&v, 1);
863 }
864
865 private int
psd_write_16(psd_write_ctx * xc,bits16 v)866 psd_write_16(psd_write_ctx *xc, bits16 v)
867 {
868 bits16 buf;
869
870 assign_u16(buf, v);
871 return psd_write(xc, (byte *)&buf, 2);
872 }
873
874 private int
psd_write_32(psd_write_ctx * xc,bits32 v)875 psd_write_32(psd_write_ctx *xc, bits32 v)
876 {
877 bits32 buf;
878
879 assign_u32(buf, v);
880 return psd_write(xc, (byte *)&buf, 4);
881 }
882
883 private int
psd_write_header(psd_write_ctx * xc,psd_device * pdev)884 psd_write_header(psd_write_ctx *xc, psd_device *pdev)
885 {
886 int code = 0;
887 int bytes_pp = xc->num_channels;
888 int chan_idx;
889 int chan_names_len = 0;
890 int sep_num;
891 const devn_separation_name *separation_name;
892
893 psd_write(xc, (const byte *)"8BPS", 4); /* Signature */
894 psd_write_16(xc, 1); /* Version - Always equal to 1*/
895 /* Reserved 6 Bytes - Must be zero */
896 psd_write_32(xc, 0);
897 psd_write_16(xc, 0);
898 psd_write_16(xc, (bits16) bytes_pp); /* Channels (2 Bytes) - Supported range is 1 to 24 */
899 psd_write_32(xc, xc->height); /* Rows */
900 psd_write_32(xc, xc->width); /* Columns */
901 psd_write_16(xc, 8); /* Depth - 1, 8 and 16 */
902 psd_write_16(xc, (bits16) xc->base_bytes_pp); /* Mode - RGB=3, CMYK=4 */
903
904 /* Color Mode Data */
905 psd_write_32(xc, 0); /* No color mode data */
906
907 /* Image Resources */
908
909 /* Channel Names */
910 for (chan_idx = NUM_CMYK_COMPONENTS; chan_idx < xc->num_channels; chan_idx++) {
911 sep_num = xc->chnl_to_orig_sep[chan_idx] - NUM_CMYK_COMPONENTS;
912 separation_name = &(pdev->devn_params.separations.names[sep_num]);
913 chan_names_len += (separation_name->size + 1);
914 }
915 psd_write_32(xc, 12 + (chan_names_len + (chan_names_len % 2))
916 + (12 + (14 * (xc->num_channels - xc->base_bytes_pp)))
917 + 28);
918 psd_write(xc, (const byte *)"8BIM", 4);
919 psd_write_16(xc, 1006); /* 0x03EE */
920 psd_write_16(xc, 0); /* PString */
921 psd_write_32(xc, chan_names_len + (chan_names_len % 2));
922 for (chan_idx = NUM_CMYK_COMPONENTS; chan_idx < xc->num_channels; chan_idx++) {
923 sep_num = xc->chnl_to_orig_sep[chan_idx] - NUM_CMYK_COMPONENTS;
924 separation_name = &(pdev->devn_params.separations.names[sep_num]);
925 psd_write_8(xc, (byte) separation_name->size);
926 psd_write(xc, separation_name->data, separation_name->size);
927 }
928 if (chan_names_len % 2)
929 psd_write_8(xc, 0); /* pad */
930
931 /* DisplayInfo - Colors for each spot channels */
932 psd_write(xc, (const byte *)"8BIM", 4);
933 psd_write_16(xc, 1007); /* 0x03EF */
934 psd_write_16(xc, 0); /* PString */
935 psd_write_32(xc, 14 * (xc->num_channels - xc->base_bytes_pp)); /* Length */
936 for (chan_idx = NUM_CMYK_COMPONENTS; chan_idx < xc->num_channels; chan_idx++) {
937 sep_num = xc->chnl_to_orig_sep[chan_idx] - NUM_CMYK_COMPONENTS;
938 psd_write_16(xc, 02); /* CMYK */
939 /* PhotoShop stores all component values as if they were additive. */
940 if (pdev->equiv_cmyk_colors.color[sep_num].color_info_valid) {
941 #define convert_color(component) ((bits16)((65535 * ((double)\
942 (frac_1 - pdev->equiv_cmyk_colors.color[sep_num].component)) / frac_1)))
943 psd_write_16(xc, convert_color(c)); /* Cyan */
944 psd_write_16(xc, convert_color(m)); /* Magenta */
945 psd_write_16(xc, convert_color(y)); /* Yellow */
946 psd_write_16(xc, convert_color(k)); /* Black */
947 #undef convert_color
948 }
949 else { /* Else set C = M = Y = 0, K = 1 */
950 psd_write_16(xc, 65535); /* Cyan */
951 psd_write_16(xc, 65535); /* Magenta */
952 psd_write_16(xc, 65535); /* Yellow */
953 psd_write_16(xc, 0); /* Black */
954 }
955 psd_write_16(xc, 0); /* Opacity 0 to 100 */
956 psd_write_8(xc, 2); /* Don't know */
957 psd_write_8(xc, 0); /* Padding - Always Zero */
958 }
959
960 /* Image resolution */
961 psd_write(xc, (const byte *)"8BIM", 4);
962 psd_write_16(xc, 1005); /* 0x03ED */
963 psd_write_16(xc, 0); /* PString */
964 psd_write_32(xc, 16); /* Length */
965 /* Resolution is specified as a fixed 16.16 bits */
966 psd_write_32(xc, (int) (pdev->HWResolution[0] * 0x10000 + 0.5));
967 psd_write_16(xc, 1); /* width: 1 --> resolution is pixels per inch */
968 psd_write_16(xc, 1); /* width: 1 --> resolution is pixels per inch */
969 psd_write_32(xc, (int) (pdev->HWResolution[1] * 0x10000 + 0.5));
970 psd_write_16(xc, 1); /* height: 1 --> resolution is pixels per inch */
971 psd_write_16(xc, 1); /* height: 1 --> resolution is pixels per inch */
972
973 /* Layer and Mask information */
974 psd_write_32(xc, 0); /* No layer or mask information */
975
976 return code;
977 }
978
979 private void
psd_calib_row(psd_write_ctx * xc,byte ** tile_data,const byte * row,int channel,icmLuBase * luo)980 psd_calib_row(psd_write_ctx *xc, byte **tile_data, const byte *row,
981 int channel, icmLuBase *luo)
982 {
983 int base_bytes_pp = xc->base_bytes_pp;
984 int n_extra_channels = xc->n_extra_channels;
985 int channels = base_bytes_pp + n_extra_channels;
986 int inn, outn;
987 int x;
988 double in[MAX_CHAN], out[MAX_CHAN];
989
990 luo->spaces(luo, NULL, &inn, NULL, &outn, NULL, NULL, NULL, NULL);
991
992 for (x = 0; x < xc->width; x++) {
993 if (channel < outn) {
994 int plane_idx;
995
996 for (plane_idx = 0; plane_idx < inn; plane_idx++)
997 in[plane_idx] = row[x*channels+plane_idx] * (1.0 / 255);
998
999 (*tile_data)[x] = (int)(0.5 + 255 * out[channel]);
1000 luo->lookup(luo, out, in);
1001 } else {
1002 (*tile_data)[x] = 255 ^ row[x*channels+base_bytes_pp+channel];
1003 }
1004 }
1005 }
1006
1007 /*
1008 * Output the image data for the PSD device. The data for the PSD is
1009 * written in separate planes. If the device is psdrgb then we simply
1010 * write three planes of RGB data. The DeviceN parameters (SeparationOrder,
1011 * SeparationCOlorNames, and MaxSeparations) are not applied to the psdrgb
1012 * device.
1013 *
1014 * The DeviceN parameters are applied to the psdcmyk device. If the
1015 * SeparationOrder parameter is not specified then first we write out the data
1016 * for the CMYK planes and then any separation planes. If the SeparationOrder
1017 * parameter is specified, then things are more complicated. Logically we
1018 * would simply write the planes specified by the SeparationOrder data.
1019 * However Photoshop expects there to be CMYK data. First we will write out
1020 * four planes of data for CMYK. If any of these colors are present in the
1021 * SeparationOrder data then the plane data will contain the color information.
1022 * If a color is not present then the plane data will be zero. After the CMYK
1023 * data, we will write out any separation data which is specified in the
1024 * SeparationOrder data.
1025 */
1026 private int
psd_write_image_data(psd_write_ctx * xc,gx_device_printer * pdev)1027 psd_write_image_data(psd_write_ctx *xc, gx_device_printer *pdev)
1028 {
1029 int code = 0;
1030 int raster = gdev_prn_raster(pdev);
1031 int i, j;
1032 byte *line, *sep_line;
1033 int base_bytes_pp = xc->base_bytes_pp;
1034 int bytes_pp =pdev->color_info.num_components;
1035 int chan_idx;
1036 psd_device *xdev = (psd_device *)pdev;
1037 icmLuBase *luo = xdev->lu_out;
1038 byte *row;
1039
1040 psd_write_16(xc, 0); /* Compression */
1041
1042 line = gs_alloc_bytes(pdev->memory, raster, "psd_write_image_data");
1043 sep_line = gs_alloc_bytes(pdev->memory, xc->width, "psd_write_sep_line");
1044
1045 /* Print the output planes */
1046 for (chan_idx = 0; chan_idx < xc->num_channels; chan_idx++) {
1047 for (j = 0; j < xc->height; ++j) {
1048 int data_pos = xc->chnl_to_position[chan_idx];
1049
1050 /* Check if the separation is present in the SeparationOrder */
1051 if (data_pos >= 0) {
1052 code = gdev_prn_get_bits(pdev, j, line, &row);
1053 if (luo == NULL) {
1054 for (i = 0; i < xc->width; ++i) {
1055 if (base_bytes_pp == 3) {
1056 /* RGB */
1057 sep_line[i] = row[i*bytes_pp + data_pos];
1058 } else {
1059 /* CMYK */
1060 sep_line[i] = 255 - row[i*bytes_pp + data_pos];
1061 }
1062 }
1063 } else {
1064 psd_calib_row(xc, &sep_line, row, data_pos, luo);
1065 }
1066 psd_write(xc, sep_line, xc->width);
1067 } else {
1068 if (chan_idx < NUM_CMYK_COMPONENTS) {
1069 /* Write empty process color */
1070 for (i = 0; i < xc->width; ++i)
1071 sep_line[i] = 255;
1072 psd_write(xc, sep_line, xc->width);
1073 }
1074 }
1075 }
1076 }
1077
1078 gs_free_object(pdev->memory, sep_line, "psd_write_sep_line");
1079 gs_free_object(pdev->memory, line, "psd_write_image_data");
1080 return code;
1081 }
1082
1083 static int
psd_print_page(gx_device_printer * pdev,FILE * file)1084 psd_print_page(gx_device_printer *pdev, FILE *file)
1085 {
1086 psd_write_ctx xc;
1087
1088 xc.f = file;
1089
1090 psd_setup(&xc, (psd_device *)pdev);
1091 psd_write_header(&xc, (psd_device *)pdev);
1092 psd_write_image_data(&xc, pdev);
1093
1094 return 0;
1095 }
1096