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