xref: /plan9/sys/src/cmd/gs/src/gdevpsdp.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1997, 1998, 1999 Aladdin Enterprises.  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: gdevpsdp.c,v 1.14 2004/06/30 14:35:37 igor Exp $ */
18 /* (Distiller) parameter handling for PostScript and PDF writers */
19 #include "string_.h"
20 #include "jpeglib_.h"		/* for sdct.h */
21 #include "gx.h"
22 #include "gserrors.h"
23 #include "gsutil.h"
24 #include "gxdevice.h"
25 #include "gsparamx.h"
26 #include "gdevpsdf.h"
27 #include "strimpl.h"		/* for short-sighted compilers */
28 #include "scfx.h"
29 #include "sdct.h"
30 #include "slzwx.h"
31 #include "spprint.h"
32 #include "srlx.h"
33 #include "szlibx.h"
34 
35 /* Define a (bogus) GC descriptor for gs_param_string. */
36 /* The only ones we use are GC-able and not persistent. */
37 gs_private_st_composite(st_gs_param_string, gs_param_string, "gs_param_string",
38 			param_string_enum_ptrs, param_string_reloc_ptrs);
39 private
40 ENUM_PTRS_WITH(param_string_enum_ptrs, gs_param_string *pstr) return 0;
41 case 0: return ENUM_CONST_STRING(pstr);
42 ENUM_PTRS_END
43 private
RELOC_PTRS_WITH(param_string_reloc_ptrs,gs_param_string * pstr)44 RELOC_PTRS_WITH(param_string_reloc_ptrs, gs_param_string *pstr)
45 {
46     gs_const_string str;
47 
48     str.data = pstr->data, str.size = pstr->size;
49     RELOC_CONST_STRING_VAR(str);
50     pstr->data = str.data;
51 }
52 RELOC_PTRS_END
53 gs_private_st_element(st_param_string_element, gs_param_string,
54 		      "gs_param_string[]", param_string_elt_enum_ptrs,
55 		      param_string_elt_reloc_ptrs, st_gs_param_string);
56 
57 
58 /* ---------------- Get/put Distiller parameters ---------------- */
59 
60 /*
61  * ColorConversionStrategy is supposed to affect output color space
62  * according to the following table.  ****** NOT IMPLEMENTED YET ******
63 
64 PS Input:  LeaveCU UseDIC           UseDICFI         sRGB
65 Gray art   Gray    CalGray/ICCBased Gray             Gray
66 Gray image Gray    CalGray/ICCBased CalGray/ICCBased Gray
67 RGB art    RGB     CalGray/ICCBased RGB              CalRGB/sRGB
68 RGB image  RGB     CalGray/ICCBased CalRGB/ICCBased  CalRGB/sRGB
69 CMYK art   CMYK    LAB/ICCBased     CMYK             CalRGB/sRGB
70 CMYK image CMYK    LAB/ICCBased     LAB/ICCBased     CalRGB/sRGB
71 CIE art    Cal/ICC Cal/ICC          Cal/ICC          CalRGB/sRGB
72 CIE image  Cal/ICC Cal/ICC          Cal/ICC          CalRGB/sRGB
73 
74  */
75 
76 /*
77  * The Always/NeverEmbed parameters are defined as being incremental.  Since
78  * this isn't compatible with the general property of page devices that if
79  * you do a currentpagedevice, doing a setpagedevice later will restore the
80  * same state, we actually define the parameters in sets of 3:
81  *	- AlwaysEmbed is used for incremental additions.
82  *	- ~AlwaysEmbed is used for incremental deletions.
83  *	- .AlwaysEmbed is used for the complete list.
84  * and analogously for NeverEmbed.
85  */
86 
87 typedef struct psdf_image_filter_name_s {
88     const char *pname;
89     const stream_template *template;
90     psdf_version min_version;
91 } psdf_image_filter_name;
92 
93 private const psdf_image_filter_name Poly_filters[] = {
94     {"DCTEncode", &s_DCTE_template},
95     {"FlateEncode", &s_zlibE_template, psdf_version_ll3},
96     {"LZWEncode", &s_LZWE_template},
97     {0, 0}
98 };
99 
100 private const psdf_image_filter_name Mono_filters[] = {
101     {"CCITTFaxEncode", &s_CFE_template},
102     {"FlateEncode", &s_zlibE_template, psdf_version_ll3},
103     {"LZWEncode", &s_LZWE_template},
104     {"RunLengthEncode", &s_RLE_template},
105     {0, 0}
106 };
107 
108 typedef struct psdf_image_param_names_s {
109     const char *ACSDict;	/* not used for mono */
110     const char *Dict;
111     const char *DownsampleType;
112     float DownsampleThreshold_default;
113     const psdf_image_filter_name *filter_names;
114     const char *Filter;
115     gs_param_item_t items[8];	/* AutoFilter (not used for mono), */
116 				/* AntiAlias, */
117 				/* Depth, Downsample, DownsampleThreshold, */
118 				/* Encode, Resolution, end marker */
119 } psdf_image_param_names_t;
120 #define pi(key, type, memb) { key, type, offset_of(psdf_image_params, memb) }
121 #define psdf_image_param_names(acs, aa, af, de, di, ds, dt, dst, dstd, e, f, fns, r)\
122     acs, di, dt, dstd, fns, f, {\
123       pi(af, gs_param_type_bool, AutoFilter),\
124       pi(aa, gs_param_type_bool, AntiAlias),\
125       pi(de, gs_param_type_int, Depth),\
126       pi(ds, gs_param_type_bool, Downsample),\
127       pi(dst, gs_param_type_float, DownsampleThreshold),\
128       pi(e, gs_param_type_bool, Encode),\
129       pi(r, gs_param_type_int, Resolution),\
130       gs_param_item_end\
131     }
132 
133 private const psdf_image_param_names_t Color_names = {
134     psdf_image_param_names(
135 	"ColorACSImageDict", "AntiAliasColorImages", "AutoFilterColorImages",
136 	"ColorImageDepth", "ColorImageDict",
137 	"DownsampleColorImages", "ColorImageDownsampleType",
138 	"ColorImageDownsampleThreshold", 1.5,
139 	"EncodeColorImages", "ColorImageFilter", Poly_filters,
140 	"ColorImageResolution"
141     )
142 };
143 private const psdf_image_param_names_t Gray_names = {
144     psdf_image_param_names(
145 	"GrayACSImageDict", "AntiAliasGrayImages", "AutoFilterGrayImages",
146 	"GrayImageDepth", "GrayImageDict",
147 	"DownsampleGrayImages", "GrayImageDownsampleType",
148 	"GrayImageDownsampleThreshold", 2.0,
149 	"EncodeGrayImages", "GrayImageFilter", Poly_filters,
150 	"GrayImageResolution"
151     )
152 };
153 private const psdf_image_param_names_t Mono_names = {
154     psdf_image_param_names(
155 	0, "AntiAliasMonoImages", 0,
156 	"MonoImageDepth", "MonoImageDict",
157 	"DownsampleMonoImages", "MonoImageDownsampleType",
158 	"MonoImageDownsampleThreshold", 2.0,
159 	"EncodeMonoImages", "MonoImageFilter", Mono_filters,
160 	"MonoImageResolution"
161     )
162 };
163 #undef pi
164 private const char *const AutoRotatePages_names[] = {
165     psdf_arp_names, 0
166 };
167 private const char *const ColorConversionStrategy_names[] = {
168     psdf_ccs_names, 0
169 };
170 private const char *const DownsampleType_names[] = {
171     psdf_ds_names, 0
172 };
173 private const char *const Binding_names[] = {
174     psdf_binding_names, 0
175 };
176 private const char *const DefaultRenderingIntent_names[] = {
177     psdf_ri_names, 0
178 };
179 private const char *const TransferFunctionInfo_names[] = {
180     psdf_tfi_names, 0
181 };
182 private const char *const UCRandBGInfo_names[] = {
183     psdf_ucrbg_names, 0
184 };
185 private const char *const CannotEmbedFontPolicy_names[] = {
186     psdf_cefp_names, 0
187 };
188 
189 private const gs_param_item_t psdf_param_items[] = {
190 #define pi(key, type, memb) { key, type, offset_of(psdf_distiller_params, memb) }
191 
192     /* General parameters */
193 
194     pi("ASCII85EncodePages", gs_param_type_bool, ASCII85EncodePages),
195     /* (AutoRotatePages) */
196     /* (Binding) */
197     pi("CompressPages", gs_param_type_bool, CompressPages),
198     /* (DefaultRenderingIntent) */
199     pi("DetectBlends", gs_param_type_bool, DetectBlends),
200     pi("DoThumbnails", gs_param_type_bool, DoThumbnails),
201     pi("ImageMemory", gs_param_type_long, ImageMemory),
202     /* (LockDistillerParams) */
203     pi("LZWEncodePages", gs_param_type_bool, LZWEncodePages),
204     pi("OPM", gs_param_type_int, OPM),
205     pi("PreserveHalftoneInfo", gs_param_type_bool, PreserveHalftoneInfo),
206     pi("PreserveOPIComments", gs_param_type_bool, PreserveOPIComments),
207     pi("PreserveOverprintSettings", gs_param_type_bool, PreserveOverprintSettings),
208     /* (TransferFunctionInfo) */
209     /* (UCRandBGInfo) */
210     pi("UseFlateCompression", gs_param_type_bool, UseFlateCompression),
211 
212     /* Color image processing parameters */
213 
214     pi("ConvertCMYKImagesToRGB", gs_param_type_bool, ConvertCMYKImagesToRGB),
215     pi("ConvertImagesToIndexed", gs_param_type_bool, ConvertImagesToIndexed),
216 
217     /* Font embedding parameters */
218 
219     /* (CannotEmbedFontPolicy) */
220     pi("EmbedAllFonts", gs_param_type_bool, EmbedAllFonts),
221     pi("MaxSubsetPct", gs_param_type_int, MaxSubsetPct),
222     pi("SubsetFonts", gs_param_type_bool, SubsetFonts),
223 
224 #undef pi
225     gs_param_item_end
226 };
227 
228 /* -------- Get parameters -------- */
229 
230 private int
psdf_write_name(gs_param_list * plist,const char * key,const char * str)231 psdf_write_name(gs_param_list *plist, const char *key, const char *str)
232 {
233     gs_param_string pstr;
234 
235     param_string_from_string(pstr, str);
236     return param_write_name(plist, key, &pstr);
237 }
238 
239 private int
psdf_write_string_param(gs_param_list * plist,const char * key,const gs_const_string * pstr)240 psdf_write_string_param(gs_param_list *plist, const char *key,
241 			const gs_const_string *pstr)
242 {
243     gs_param_string ps;
244 
245     ps.data = pstr->data;
246     ps.size = pstr->size;
247     ps.persistent = false;
248     return param_write_string(plist, key, &ps);
249 }
250 
251 /*
252  * Get an image Dict parameter.  Note that we return a default (empty)
253  * dictionary if the parameter has never been set.
254  */
255 private int
psdf_get_image_dict_param(gs_param_list * plist,const gs_param_name pname,gs_c_param_list * plvalue)256 psdf_get_image_dict_param(gs_param_list * plist, const gs_param_name pname,
257 			  gs_c_param_list *plvalue)
258 {
259     gs_param_dict dict;
260     int code;
261 
262     if (pname == 0)
263 	return 0;
264     dict.size = 12;		/* enough for all param dicts we know about */
265     if ((code = param_begin_write_dict(plist, pname, &dict, false)) < 0)
266 	return code;
267     if (plvalue != 0) {
268 	gs_c_param_list_read(plvalue);
269 	code = param_list_copy(dict.list, (gs_param_list *)plvalue);
270     }
271     param_end_write_dict(plist, pname, &dict);
272     return code;
273 }
274 
275 /* Get a set of image-related parameters. */
276 private int
psdf_get_image_params(gs_param_list * plist,const psdf_image_param_names_t * pnames,psdf_image_params * params)277 psdf_get_image_params(gs_param_list * plist,
278 	  const psdf_image_param_names_t * pnames, psdf_image_params * params)
279 {
280     /* Skip AutoFilter for mono images. */
281     const gs_param_item_t *items =
282 	(pnames->items[0].key == 0 ? pnames->items + 1 : pnames->items);
283     int code;
284 
285     /*
286      * We must actually return a value for every parameter, so that
287      * all parameter names will be recognized as settable by -d or -s
288      * from the command line.
289      */
290     if (
291 	   (code = gs_param_write_items(plist, params, NULL, items)) < 0 ||
292 	   (code = psdf_get_image_dict_param(plist, pnames->ACSDict,
293 					     params->ACSDict)) < 0 ||
294 	   /* (AntiAlias) */
295 	   /* (AutoFilter) */
296 	   /* (Depth) */
297 	   (code = psdf_get_image_dict_param(plist, pnames->Dict,
298 					     params->Dict)) < 0 ||
299 	   /* (Downsample) */
300 	   (code = psdf_write_name(plist, pnames->DownsampleType,
301 		DownsampleType_names[params->DownsampleType])) < 0 ||
302 	   /* (DownsampleThreshold) */
303 	   /* (Encode) */
304 	   (code = psdf_write_name(plist, pnames->Filter,
305 				   (params->Filter == 0 ?
306 				    pnames->filter_names[0].pname :
307 				    params->Filter))) < 0
308 	   /* (Resolution) */
309 	)
310 	DO_NOTHING;
311     return code;
312 }
313 
314 /* Get a font embedding parameter. */
315 private int
psdf_get_embed_param(gs_param_list * plist,gs_param_name allpname,const gs_param_string_array * psa)316 psdf_get_embed_param(gs_param_list *plist, gs_param_name allpname,
317 		     const gs_param_string_array *psa)
318 {
319     int code = param_write_name_array(plist, allpname, psa);
320 
321     if (code >= 0)
322 	code = param_write_name_array(plist, allpname + 1, psa);
323     return code;
324 }
325 
326 /* Get parameters. */
327 int
gdev_psdf_get_params(gx_device * dev,gs_param_list * plist)328 gdev_psdf_get_params(gx_device * dev, gs_param_list * plist)
329 {
330     gx_device_psdf *pdev = (gx_device_psdf *) dev;
331     int code = gdev_vector_get_params(dev, plist);
332 
333     if (
334 	code < 0 ||
335 	(code = gs_param_write_items(plist, &pdev->params, NULL, psdf_param_items)) < 0 ||
336 
337     /* General parameters */
338 
339 	(code = psdf_write_name(plist, "AutoRotatePages",
340 		AutoRotatePages_names[(int)pdev->params.AutoRotatePages])) < 0 ||
341 	(code = psdf_write_name(plist, "Binding",
342 		Binding_names[(int)pdev->params.Binding])) < 0 ||
343 	(code = psdf_write_name(plist, "DefaultRenderingIntent",
344 		DefaultRenderingIntent_names[(int)pdev->params.DefaultRenderingIntent])) < 0 ||
345 	(code = psdf_write_name(plist, "TransferFunctionInfo",
346 		TransferFunctionInfo_names[(int)pdev->params.TransferFunctionInfo])) < 0 ||
347 	(code = psdf_write_name(plist, "UCRandBGInfo",
348 		UCRandBGInfo_names[(int)pdev->params.UCRandBGInfo])) < 0 ||
349 
350     /* Color sampled image parameters */
351 
352 	(code = psdf_get_image_params(plist, &Color_names, &pdev->params.ColorImage)) < 0 ||
353 	(code = psdf_write_name(plist, "ColorConversionStrategy",
354 		ColorConversionStrategy_names[(int)pdev->params.ColorConversionStrategy])) < 0 ||
355 	(code = psdf_write_string_param(plist, "CalCMYKProfile",
356 					&pdev->params.CalCMYKProfile)) < 0 ||
357 	(code = psdf_write_string_param(plist, "CalGrayProfile",
358 					&pdev->params.CalGrayProfile)) < 0 ||
359 	(code = psdf_write_string_param(plist, "CalRGBProfile",
360 					&pdev->params.CalRGBProfile)) < 0 ||
361 	(code = psdf_write_string_param(plist, "sRGBProfile",
362 					&pdev->params.sRGBProfile)) < 0 ||
363 
364     /* Gray sampled image parameters */
365 
366 	(code = psdf_get_image_params(plist, &Gray_names, &pdev->params.GrayImage)) < 0 ||
367 
368     /* Mono sampled image parameters */
369 
370 	(code = psdf_get_image_params(plist, &Mono_names, &pdev->params.MonoImage)) < 0 ||
371 
372     /* Font embedding parameters */
373 
374 	(code = psdf_get_embed_param(plist, ".AlwaysEmbed", &pdev->params.AlwaysEmbed)) < 0 ||
375 	(code = psdf_get_embed_param(plist, ".NeverEmbed", &pdev->params.NeverEmbed)) < 0 ||
376 	(code = psdf_write_name(plist, "CannotEmbedFontPolicy",
377 		CannotEmbedFontPolicy_names[(int)pdev->params.CannotEmbedFontPolicy])) < 0
378 	)
379 	DO_NOTHING;
380     return code;
381 }
382 
383 /* -------- Put parameters -------- */
384 
385 extern stream_state_proc_put_params(s_CF_put_params, stream_CF_state);
386 extern stream_state_proc_put_params(s_DCTE_put_params, stream_DCT_state);
387 typedef stream_state_proc_put_params((*ss_put_params_t), stream_state);
388 
389 private int
psdf_read_string_param(gs_param_list * plist,const char * key,gs_const_string * pstr,gs_memory_t * mem,int ecode)390 psdf_read_string_param(gs_param_list *plist, const char *key,
391 		       gs_const_string *pstr, gs_memory_t *mem, int ecode)
392 {
393     gs_param_string ps;
394     int code;
395 
396     switch (code = param_read_string(plist, key, &ps)) {
397     case 0: {
398 	uint size = ps.size;
399 	byte *data = gs_alloc_string(mem, size, "psdf_read_string_param");
400 
401 	if (data == 0)
402 	    return_error(gs_error_VMerror);
403 	memcpy(data, ps.data, size);
404 	pstr->data = data;
405 	pstr->size = size;
406 	break;
407     }
408     default:
409 	ecode = code;
410     case 1:
411 	break;
412     }
413     return ecode;
414 }
415 
416 /*
417  * The arguments and return value for psdf_put_enum are different because
418  * we must cast the value both going in and coming out.
419  */
420 private int
psdf_put_enum(gs_param_list * plist,const char * key,int value,const char * const pnames[],int * pecode)421 psdf_put_enum(gs_param_list *plist, const char *key, int value,
422 	      const char *const pnames[], int *pecode)
423 {
424     *pecode = param_put_enum(plist, key, &value, pnames, *pecode);
425     return value;
426 }
427 
428 private int
psdf_CF_put_params(gs_param_list * plist,stream_state * st)429 psdf_CF_put_params(gs_param_list * plist, stream_state * st)
430 {
431     stream_CFE_state *const ss = (stream_CFE_state *) st;
432 
433     (*s_CFE_template.set_defaults) (st);
434     ss->K = -1;
435     ss->BlackIs1 = true;
436     return s_CF_put_params(plist, (stream_CF_state *) ss);
437 }
438 
439 private int
psdf_DCT_put_params(gs_param_list * plist,stream_state * st)440 psdf_DCT_put_params(gs_param_list * plist, stream_state * st)
441 {
442     return psdf_DCT_filter(plist, st, 8 /*nominal*/, 8 /*ibid.*/, 3 /*ibid.*/,
443 			   NULL);
444 }
445 
446 /* Put [~](Always|Never)Embed parameters. */
447 private int
param_read_embed_array(gs_param_list * plist,gs_param_name pname,gs_param_string_array * psa,int ecode)448 param_read_embed_array(gs_param_list * plist, gs_param_name pname,
449 		       gs_param_string_array * psa, int ecode)
450 {
451     int code;
452 
453     psa->data = 0, psa->size = 0;
454     switch (code = param_read_name_array(plist, pname, psa)) {
455 	default:
456 	    ecode = code;
457 	    param_signal_error(plist, pname, ecode);
458 	case 0:
459 	case 1:
460 	    break;
461     }
462     return ecode;
463 }
464 private bool
param_string_eq(const gs_param_string * ps1,const gs_param_string * ps2)465 param_string_eq(const gs_param_string *ps1, const gs_param_string *ps2)
466 {
467     return !bytes_compare(ps1->data, ps1->size, ps2->data, ps2->size);
468 }
469 private int
add_embed(gs_param_string_array * prsa,const gs_param_string_array * psa,gs_memory_t * mem)470 add_embed(gs_param_string_array *prsa, const gs_param_string_array *psa,
471 	  gs_memory_t *mem)
472 {
473     uint i;
474     gs_param_string *const rdata =
475 	(gs_param_string *)prsa->data; /* break const */
476     uint count = prsa->size;
477 
478     for (i = 0; i < psa->size; ++i) {
479 	uint j;
480 
481 	for (j = 0; j < count; ++j)
482 	    if (param_string_eq(&psa->data[i], &rdata[j]))
483 		    break;
484 	if (j == count) {
485 	    uint size = psa->data[i].size;
486 	    byte *data = gs_alloc_string(mem, size, "add_embed");
487 
488 	    if (data == 0)
489 		return_error(gs_error_VMerror);
490 	    memcpy(data, psa->data[i].data, size);
491 	    rdata[count].data = data;
492 	    rdata[count].size = size;
493 	    rdata[count].persistent = false;
494 	    count++;
495 	}
496     }
497     prsa->size = count;
498     return 0;
499 }
500 private void
delete_embed(gs_param_string_array * prsa,const gs_param_string_array * pnsa,gs_memory_t * mem)501 delete_embed(gs_param_string_array *prsa, const gs_param_string_array *pnsa,
502 	     gs_memory_t *mem)
503 {
504     uint i;
505     gs_param_string *const rdata =
506 	(gs_param_string *)prsa->data; /* break const */
507     uint count = prsa->size;
508 
509     for (i = pnsa->size; i-- > 0;) {
510 	uint j;
511 
512 	for (j = count; j-- > 0;)
513 	    if (param_string_eq(&pnsa->data[i], &rdata[j]))
514 		break;
515 	if (j + 1 != 0) {
516 	    gs_free_const_string(mem, rdata[j].data, rdata[j].size,
517 				 "delete_embed");
518 	    rdata[j] = rdata[--count];
519 	}
520     }
521     prsa->size = count;
522 }
523 private int
psdf_put_embed_param(gs_param_list * plist,gs_param_name notpname,gs_param_name allpname,gs_param_string_array * psa,gs_memory_t * mem,int ecode)524 psdf_put_embed_param(gs_param_list * plist, gs_param_name notpname,
525 		     gs_param_name allpname, gs_param_string_array * psa,
526 		     gs_memory_t *mem, int ecode)
527 {
528     gs_param_name pname = notpname + 1;
529     gs_param_string_array sa, nsa, asa;
530     bool replace;
531     gs_param_string *rdata;
532     gs_param_string_array rsa;
533     int code = 0;
534 
535     mem = gs_memory_stable(mem);
536     ecode = param_read_embed_array(plist, pname, &sa, ecode);
537     ecode = param_read_embed_array(plist, notpname, &nsa, ecode);
538     ecode = param_read_embed_array(plist, allpname, &asa, ecode);
539     if (ecode < 0)
540 	return ecode;
541     /*
542      * Figure out whether we're replacing (sa == asa or asa and no sa,
543      * no nsa) or updating (all other cases).
544      */
545     if (asa.data == 0 || nsa.data != 0)
546 	replace = false;
547     else if (sa.data == 0)
548 	replace = true;
549     else if (sa.size != asa.size)
550 	replace = false;
551     else {
552 	/* Test whether sa == asa. */
553 	uint i;
554 
555 	replace = true;
556 	for (i = 0; i < sa.size; ++i)
557 	    if (!param_string_eq(&sa.data[i], &asa.data[i])) {
558 		replace = false;
559 		break;
560 	    }
561 	if (replace)
562 	    return 0;		/* no-op */
563     }
564     if (replace) {
565 	/* Wholesale replacement, only asa is relevant. */
566 	rdata = gs_alloc_struct_array(mem, asa.size, gs_param_string,
567 				      &st_param_string_element,
568 				      "psdf_put_embed_param(replace)");
569 	if (rdata == 0)
570 	    return_error(gs_error_VMerror);
571 	rsa.data = rdata;
572 	rsa.size = 0;
573 	if ((code = add_embed(&rsa, &asa, mem)) < 0) {
574 	    gs_free_object(mem, rdata, "psdf_put_embed_param(replace)");
575 	    ecode = code;
576 	} else
577 	    delete_embed(psa, psa, mem);
578     } else if (sa.data || nsa.data) {
579 	/* Incremental update, sa and nsa are relevant, asa is not. */
580 	rdata = gs_alloc_struct_array(mem, psa->size + sa.size,
581 				      gs_param_string,
582 				      &st_param_string_element,
583 				      "psdf_put_embed_param(update)");
584 	if (rdata == 0)
585 	    return_error(gs_error_VMerror);
586 	memcpy(rdata, psa->data, psa->size * sizeof(*psa->data));
587 	rsa.data = rdata;
588 	rsa.size = psa->size;
589 	if ((code = add_embed(&rsa, &sa, mem)) < 0) {
590 	    gs_free_object(mem, rdata, "psdf_put_embed_param(update)");
591 	    ecode = code;
592 	} else {
593 	    delete_embed(&rsa, &nsa, mem);
594 	    rsa.data = gs_resize_object(mem, rdata, rsa.size,
595 					"psdf_put_embed_param(resize)");
596 	}
597     } else
598 	return 0;		/* no-op */
599     if (code >= 0) {
600 	gs_free_const_object(mem, psa->data, "psdf_put_embed_param(free)");
601 	rsa.persistent = false;
602 	*psa = rsa;
603     }
604     return ecode;
605 }
606 
607 /* Put an image Dict parameter. */
608 private int
psdf_put_image_dict_param(gs_param_list * plist,const gs_param_name pname,gs_c_param_list ** pplvalue,const stream_template * template,ss_put_params_t put_params,gs_memory_t * mem)609 psdf_put_image_dict_param(gs_param_list * plist, const gs_param_name pname,
610 			  gs_c_param_list **pplvalue,
611 			  const stream_template * template,
612 			  ss_put_params_t put_params, gs_memory_t * mem)
613 {
614     gs_param_dict dict;
615     gs_c_param_list *plvalue = *pplvalue;
616     int code;
617 
618     mem = gs_memory_stable(mem);
619     switch (code = param_begin_read_dict(plist, pname, &dict, false)) {
620 	default:
621 	    param_signal_error(plist, pname, code);
622 	    return code;
623 	case 1:
624 	    return 0;
625 	case 0: {
626 	    /* Check the parameter values now. */
627 	    stream_state *ss = s_alloc_state(mem, template->stype, pname);
628 
629 	    if (ss == 0)
630 		return_error(gs_error_VMerror);
631 	    ss->template = template;
632 	    if (template->set_defaults)
633 		template->set_defaults(ss);
634 	    code = put_params(dict.list, ss);
635 	    if (template->release)
636 		template->release(ss);
637 	    gs_free_object(mem, ss, pname);
638 	    if (code < 0) {
639 		param_signal_error(plist, pname, code);
640 	    } else {
641 		plvalue = gs_c_param_list_alloc(mem, pname);
642 		if (plvalue == 0)
643 		    return_error(gs_error_VMerror);
644 		gs_c_param_list_write(plvalue, mem);
645 		code = param_list_copy((gs_param_list *)plvalue,
646 				       dict.list);
647 		if (code < 0) {
648 		    gs_c_param_list_release(plvalue);
649 		    gs_free_object(mem, plvalue, pname);
650 		    plvalue = *pplvalue;
651 		}
652 	    }
653 	}
654 	param_end_read_dict(plist, pname, &dict);
655 	break;
656     }
657     if (plvalue != *pplvalue) {
658 	if (*pplvalue)
659 	    gs_c_param_list_release(*pplvalue);
660 	*pplvalue = plvalue;
661     }
662     return code;
663 }
664 
665 /* Put a set of image-related parameters. */
666 private int
psdf_put_image_params(const gx_device_psdf * pdev,gs_param_list * plist,const psdf_image_param_names_t * pnames,psdf_image_params * params,int ecode)667 psdf_put_image_params(const gx_device_psdf * pdev, gs_param_list * plist,
668 		      const psdf_image_param_names_t * pnames,
669 		      psdf_image_params * params, int ecode)
670 {
671     gs_param_string fs;
672     /*
673      * Since this procedure can be called before the device is open,
674      * we must use pdev->memory rather than pdev->v_memory.
675      */
676     gs_memory_t *mem = pdev->memory;
677     gs_param_name pname;
678     /* Skip AutoFilter for mono images. */
679     const gs_param_item_t *items =
680 	(pnames->items[0].key == 0 ? pnames->items + 1 : pnames->items);
681     int code = gs_param_read_items(plist, params, items);
682 
683     if ((pname = pnames->ACSDict) != 0) {
684 	code = psdf_put_image_dict_param(plist, pname, &params->ACSDict,
685 					 &s_DCTE_template,
686 					 psdf_DCT_put_params, mem);
687 	if (code < 0)
688 	    ecode = code;
689     }
690     /* (AntiAlias) */
691     /* (AutoFilter) */
692     /* (Depth) */
693     if ((pname = pnames->Dict) != 0) {
694 	const stream_template *template;
695 	ss_put_params_t put_params;
696 
697 	/* Hack to determine what kind of a Dict we want: */
698 	if (pnames->Dict[0] == 'M')
699 	    template = &s_CFE_template,
700 		put_params = psdf_CF_put_params;
701 	else
702 	    template = &s_DCTE_template,
703 		put_params = psdf_DCT_put_params;
704 	code = psdf_put_image_dict_param(plist, pname, &params->Dict,
705 					 template, put_params, mem);
706 	if (code < 0)
707 	    ecode = code;
708     }
709     /* (Downsample) */
710     params->DownsampleType = (enum psdf_downsample_type)
711 	psdf_put_enum(plist, pnames->DownsampleType,
712 		      (int)params->DownsampleType, DownsampleType_names,
713 		      &ecode);
714     /* (DownsampleThreshold) */
715     /* (Encode) */
716     switch (code = param_read_string(plist, pnames->Filter, &fs)) {
717 	case 0:
718 	    {
719 		const psdf_image_filter_name *pn = pnames->filter_names;
720 
721 		while (pn->pname != 0 && !gs_param_string_eq(&fs, pn->pname))
722 		    pn++;
723 		if (pn->pname == 0 || pn->min_version > pdev->version) {
724 		    ecode = gs_error_rangecheck;
725 		    goto ipe;
726 		}
727 		params->Filter = pn->pname;
728 		params->filter_template = pn->template;
729 		break;
730 	    }
731 	default:
732 	    ecode = code;
733 	  ipe:param_signal_error(plist, pnames->Filter, ecode);
734 	case 1:
735 	    break;
736     }
737     /* (Resolution) */
738     if (ecode >= 0) {		/* Force parameters to acceptable values. */
739 	if (params->Resolution < 1)
740 	    params->Resolution = 1;
741 	if (params->DownsampleThreshold < 1 ||
742 	    params->DownsampleThreshold > 10)
743 	    params->DownsampleThreshold = pnames->DownsampleThreshold_default;
744 	switch (params->Depth) {
745 	    default:
746 		params->Depth = -1;
747 	    case 1:
748 	    case 2:
749 	    case 4:
750 	    case 8:
751 	    case -1:
752 		break;
753 	}
754     }
755     return ecode;
756 }
757 
758 /* Put parameters. */
759 int
gdev_psdf_put_params(gx_device * dev,gs_param_list * plist)760 gdev_psdf_put_params(gx_device * dev, gs_param_list * plist)
761 {
762     gx_device_psdf *pdev = (gx_device_psdf *) dev;
763     gs_memory_t *mem =
764 	(pdev->v_memory ? pdev->v_memory : dev->memory);
765     int ecode, code;
766     psdf_distiller_params params;
767 
768     params = pdev->params;
769 
770     /*
771      * If LockDistillerParams was true and isn't being set to false,
772      * ignore all other psdf parameters.  However, do not ignore the
773      * standard device parameters.
774      */
775     ecode = code = param_read_bool(plist, "LockDistillerParams",
776   				   &params.LockDistillerParams);
777     if (!(pdev->params.LockDistillerParams && params.LockDistillerParams)) {
778 
779 	/* General parameters. */
780 
781 	code = gs_param_read_items(plist, &params, psdf_param_items);
782 	if (code < 0)
783 	    ecode = code;
784 	params.AutoRotatePages = (enum psdf_auto_rotate_pages)
785 	    psdf_put_enum(plist, "AutoRotatePages", (int)params.AutoRotatePages,
786 			  AutoRotatePages_names, &ecode);
787 	params.Binding = (enum psdf_binding)
788 	    psdf_put_enum(plist, "Binding", (int)params.Binding,
789 			  Binding_names, &ecode);
790 	params.DefaultRenderingIntent = (enum psdf_default_rendering_intent)
791 	    psdf_put_enum(plist, "DefaultRenderingIntent",
792 			  (int)params.DefaultRenderingIntent,
793 			  DefaultRenderingIntent_names, &ecode);
794 	params.TransferFunctionInfo = (enum psdf_transfer_function_info)
795 	    psdf_put_enum(plist, "TransferFunctionInfo",
796 			  (int)params.TransferFunctionInfo,
797 			  TransferFunctionInfo_names, &ecode);
798 	params.UCRandBGInfo = (enum psdf_ucr_and_bg_info)
799 	    psdf_put_enum(plist, "UCRandBGInfo", (int)params.UCRandBGInfo,
800 			  UCRandBGInfo_names, &ecode);
801 	ecode = param_put_bool(plist, "UseFlateCompression",
802 			       &params.UseFlateCompression, ecode);
803 
804 	/* Color sampled image parameters */
805 
806 	ecode = psdf_put_image_params(pdev, plist, &Color_names,
807 				      &params.ColorImage, ecode);
808 	params.ColorConversionStrategy = (enum psdf_color_conversion_strategy)
809 	    psdf_put_enum(plist, "ColorConversionStrategy",
810 			  (int)params.ColorConversionStrategy,
811 			  ColorConversionStrategy_names, &ecode);
812 	ecode = psdf_read_string_param(plist, "CalCMYKProfile",
813 				       &params.CalCMYKProfile, mem, ecode);
814 	ecode = psdf_read_string_param(plist, "CalGrayProfile",
815 				       &params.CalGrayProfile, mem, ecode);
816 	ecode = psdf_read_string_param(plist, "CalRGBProfile",
817 				       &params.CalRGBProfile, mem, ecode);
818 	ecode = psdf_read_string_param(plist, "sRGBProfile",
819 				       &params.sRGBProfile, mem, ecode);
820 
821 	/* Gray sampled image parameters */
822 
823 	ecode = psdf_put_image_params(pdev, plist, &Gray_names,
824 				      &params.GrayImage, ecode);
825 
826 	/* Mono sampled image parameters */
827 
828 	ecode = psdf_put_image_params(pdev, plist, &Mono_names,
829 				      &params.MonoImage, ecode);
830 
831 	/* Font embedding parameters */
832 
833 	ecode = psdf_put_embed_param(plist, "~AlwaysEmbed", ".AlwaysEmbed",
834 				     &params.AlwaysEmbed, mem, ecode);
835 	ecode = psdf_put_embed_param(plist, "~NeverEmbed", ".NeverEmbed",
836 				     &params.NeverEmbed, mem, ecode);
837 	params.CannotEmbedFontPolicy = (enum psdf_cannot_embed_font_policy)
838 	    psdf_put_enum(plist, "CannotEmbedFontPolicy",
839 			  (int)params.CannotEmbedFontPolicy,
840 			  CannotEmbedFontPolicy_names, &ecode);
841     }
842     if (ecode < 0)
843 	return ecode;
844     code = gdev_vector_put_params(dev, plist);
845     if (code < 0)
846 	return code;
847 
848     pdev->params = params;	/* OK to update now */
849     return 0;
850 }
851