xref: /plan9/sys/src/cmd/gs/src/zht2.c (revision 7dd7cddf99dd7472612f1413b4da293630e6b1bc)
1*7dd7cddfSDavid du Colombier /* Copyright (C) 1992, 1995, 1996, 1997, 1998, 1999 Aladdin Enterprises.  All rights reserved.
2*7dd7cddfSDavid du Colombier 
3*7dd7cddfSDavid du Colombier    This file is part of Aladdin Ghostscript.
4*7dd7cddfSDavid du Colombier 
5*7dd7cddfSDavid du Colombier    Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
6*7dd7cddfSDavid du Colombier    or distributor accepts any responsibility for the consequences of using it,
7*7dd7cddfSDavid du Colombier    or for whether it serves any particular purpose or works at all, unless he
8*7dd7cddfSDavid du Colombier    or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
9*7dd7cddfSDavid du Colombier    License (the "License") for full details.
10*7dd7cddfSDavid du Colombier 
11*7dd7cddfSDavid du Colombier    Every copy of Aladdin Ghostscript must include a copy of the License,
12*7dd7cddfSDavid du Colombier    normally in a plain ASCII text file named PUBLIC.  The License grants you
13*7dd7cddfSDavid du Colombier    the right to copy, modify and redistribute Aladdin Ghostscript, but only
14*7dd7cddfSDavid du Colombier    under certain conditions described in the License.  Among other things, the
15*7dd7cddfSDavid du Colombier    License requires that the copyright notice and this notice be preserved on
16*7dd7cddfSDavid du Colombier    all copies.
17*7dd7cddfSDavid du Colombier  */
18*7dd7cddfSDavid du Colombier 
19*7dd7cddfSDavid du Colombier /*$Id: zht2.c,v 1.1 2000/03/09 08:40:45 lpd Exp $ */
20*7dd7cddfSDavid du Colombier /* Level 2 sethalftone operator */
21*7dd7cddfSDavid du Colombier #include "ghost.h"
22*7dd7cddfSDavid du Colombier #include "oper.h"
23*7dd7cddfSDavid du Colombier #include "gsstruct.h"
24*7dd7cddfSDavid du Colombier #include "gxdevice.h"		/* for gzht.h */
25*7dd7cddfSDavid du Colombier #include "gzht.h"
26*7dd7cddfSDavid du Colombier #include "estack.h"
27*7dd7cddfSDavid du Colombier #include "ialloc.h"
28*7dd7cddfSDavid du Colombier #include "iddict.h"
29*7dd7cddfSDavid du Colombier #include "idparam.h"
30*7dd7cddfSDavid du Colombier #include "igstate.h"
31*7dd7cddfSDavid du Colombier #include "icolor.h"
32*7dd7cddfSDavid du Colombier #include "iht.h"
33*7dd7cddfSDavid du Colombier #include "store.h"
34*7dd7cddfSDavid du Colombier 
35*7dd7cddfSDavid du Colombier /* Forward references */
36*7dd7cddfSDavid du Colombier private int dict_spot_params(P4(const ref *, gs_spot_halftone *,
37*7dd7cddfSDavid du Colombier 				ref *, ref *));
38*7dd7cddfSDavid du Colombier private int dict_spot_results(P3(i_ctx_t *, ref *, const gs_spot_halftone *));
39*7dd7cddfSDavid du Colombier private int dict_threshold_params(P3(const ref *, gs_threshold_halftone *,
40*7dd7cddfSDavid du Colombier 				     ref *));
41*7dd7cddfSDavid du Colombier private int dict_threshold2_params(P4(const ref *, gs_threshold2_halftone *,
42*7dd7cddfSDavid du Colombier 				      ref *, gs_memory_t *));
43*7dd7cddfSDavid du Colombier 
44*7dd7cddfSDavid du Colombier /* Dummy spot function */
45*7dd7cddfSDavid du Colombier private float
46*7dd7cddfSDavid du Colombier spot1_dummy(floatp x, floatp y)
47*7dd7cddfSDavid du Colombier {
48*7dd7cddfSDavid du Colombier     return (x + y) / 2;
49*7dd7cddfSDavid du Colombier }
50*7dd7cddfSDavid du Colombier 
51*7dd7cddfSDavid du Colombier /* <dict> <dict5> .sethalftone5 - */
52*7dd7cddfSDavid du Colombier private int sethalftone_finish(P1(i_ctx_t *));
53*7dd7cddfSDavid du Colombier private int sethalftone_cleanup(P1(i_ctx_t *));
54*7dd7cddfSDavid du Colombier private int
55*7dd7cddfSDavid du Colombier zsethalftone5(i_ctx_t *i_ctx_p)
56*7dd7cddfSDavid du Colombier {
57*7dd7cddfSDavid du Colombier     os_ptr op = osp;
58*7dd7cddfSDavid du Colombier     uint count;
59*7dd7cddfSDavid du Colombier     gs_halftone_component *phtc;
60*7dd7cddfSDavid du Colombier     gs_halftone_component *pc;
61*7dd7cddfSDavid du Colombier     int code = 0;
62*7dd7cddfSDavid du Colombier     int i, j;
63*7dd7cddfSDavid du Colombier     gs_halftone *pht;
64*7dd7cddfSDavid du Colombier     gx_device_halftone *pdht;
65*7dd7cddfSDavid du Colombier     static const char *const color_names[] = {
66*7dd7cddfSDavid du Colombier 	gs_ht_separation_name_strings
67*7dd7cddfSDavid du Colombier     };
68*7dd7cddfSDavid du Colombier     ref sprocs[countof(color_names)];
69*7dd7cddfSDavid du Colombier     ref tprocs[countof(color_names)];
70*7dd7cddfSDavid du Colombier     gs_memory_t *mem;
71*7dd7cddfSDavid du Colombier     uint edepth = ref_stack_count(&e_stack);
72*7dd7cddfSDavid du Colombier     int npop = 2;
73*7dd7cddfSDavid du Colombier 
74*7dd7cddfSDavid du Colombier     check_type(*op, t_dictionary);
75*7dd7cddfSDavid du Colombier     check_dict_read(*op);
76*7dd7cddfSDavid du Colombier     check_type(op[-1], t_dictionary);
77*7dd7cddfSDavid du Colombier     check_dict_read(op[-1]);
78*7dd7cddfSDavid du Colombier     count = 0;
79*7dd7cddfSDavid du Colombier     for (i = 0; i < countof(color_names); i++) {
80*7dd7cddfSDavid du Colombier 	ref *pvalue;
81*7dd7cddfSDavid du Colombier 
82*7dd7cddfSDavid du Colombier 	if (dict_find_string(op, color_names[i], &pvalue) > 0)
83*7dd7cddfSDavid du Colombier 	    count++;
84*7dd7cddfSDavid du Colombier 	else if (i == gs_ht_separation_Default)
85*7dd7cddfSDavid du Colombier 	    return_error(e_typecheck);
86*7dd7cddfSDavid du Colombier     }
87*7dd7cddfSDavid du Colombier     mem = (gs_memory_t *) idmemory->spaces_indexed[r_space_index(op - 1)];
88*7dd7cddfSDavid du Colombier     check_estack(5);		/* for sampling Type 1 screens */
89*7dd7cddfSDavid du Colombier     refset_null(sprocs, countof(sprocs));
90*7dd7cddfSDavid du Colombier     refset_null(tprocs, countof(tprocs));
91*7dd7cddfSDavid du Colombier     rc_alloc_struct_0(pht, gs_halftone, &st_halftone,
92*7dd7cddfSDavid du Colombier 		      imemory, pht = 0, ".sethalftone5");
93*7dd7cddfSDavid du Colombier     phtc = gs_alloc_struct_array(mem, count, gs_halftone_component,
94*7dd7cddfSDavid du Colombier 				 &st_ht_component_element,
95*7dd7cddfSDavid du Colombier 				 ".sethalftone5");
96*7dd7cddfSDavid du Colombier     rc_alloc_struct_0(pdht, gx_device_halftone, &st_device_halftone,
97*7dd7cddfSDavid du Colombier 		      imemory, pdht = 0, ".sethalftone5");
98*7dd7cddfSDavid du Colombier     if (pht == 0 || phtc == 0 || pdht == 0)
99*7dd7cddfSDavid du Colombier 	code = gs_note_error(e_VMerror);
100*7dd7cddfSDavid du Colombier     else
101*7dd7cddfSDavid du Colombier 	for (i = 0, j = 0, pc = phtc; i < countof(color_names); i++) {
102*7dd7cddfSDavid du Colombier 	    int type;
103*7dd7cddfSDavid du Colombier 	    ref *pvalue;
104*7dd7cddfSDavid du Colombier 
105*7dd7cddfSDavid du Colombier 	    if (dict_find_string(op, color_names[i], &pvalue) > 0) {
106*7dd7cddfSDavid du Colombier 		check_type_only(*pvalue, t_dictionary);
107*7dd7cddfSDavid du Colombier 		check_dict_read(*pvalue);
108*7dd7cddfSDavid du Colombier 		if (dict_int_param(pvalue, "HalftoneType", 1, 7, 0,
109*7dd7cddfSDavid du Colombier 				   &type) < 0
110*7dd7cddfSDavid du Colombier 		    ) {
111*7dd7cddfSDavid du Colombier 		    code = gs_note_error(e_typecheck);
112*7dd7cddfSDavid du Colombier 		    break;
113*7dd7cddfSDavid du Colombier 		}
114*7dd7cddfSDavid du Colombier 		switch (type) {
115*7dd7cddfSDavid du Colombier 		    default:
116*7dd7cddfSDavid du Colombier 			code = gs_note_error(e_rangecheck);
117*7dd7cddfSDavid du Colombier 			break;
118*7dd7cddfSDavid du Colombier 		    case 1:
119*7dd7cddfSDavid du Colombier 			code = dict_spot_params(pvalue,
120*7dd7cddfSDavid du Colombier 						&pc->params.spot, sprocs + j,
121*7dd7cddfSDavid du Colombier 						tprocs + j);
122*7dd7cddfSDavid du Colombier 			pc->params.spot.screen.spot_function = spot1_dummy;
123*7dd7cddfSDavid du Colombier 			pc->type = ht_type_spot;
124*7dd7cddfSDavid du Colombier 			break;
125*7dd7cddfSDavid du Colombier 		    case 3:
126*7dd7cddfSDavid du Colombier 			code = dict_threshold_params(pvalue,
127*7dd7cddfSDavid du Colombier 					 &pc->params.threshold, tprocs + j);
128*7dd7cddfSDavid du Colombier 			pc->type = ht_type_threshold;
129*7dd7cddfSDavid du Colombier 			break;
130*7dd7cddfSDavid du Colombier 		    case 7:
131*7dd7cddfSDavid du Colombier 			code = dict_threshold2_params(pvalue,
132*7dd7cddfSDavid du Colombier 					&pc->params.threshold2, tprocs + j,
133*7dd7cddfSDavid du Colombier 					imemory);
134*7dd7cddfSDavid du Colombier 			pc->type = ht_type_threshold2;
135*7dd7cddfSDavid du Colombier 			break;
136*7dd7cddfSDavid du Colombier 		}
137*7dd7cddfSDavid du Colombier 		if (code < 0)
138*7dd7cddfSDavid du Colombier 		    break;
139*7dd7cddfSDavid du Colombier 		pc->cname = (gs_ht_separation_name) i;
140*7dd7cddfSDavid du Colombier 		pc++, j++;
141*7dd7cddfSDavid du Colombier 	    }
142*7dd7cddfSDavid du Colombier 	}
143*7dd7cddfSDavid du Colombier     if (code >= 0) {
144*7dd7cddfSDavid du Colombier 	/*
145*7dd7cddfSDavid du Colombier 	 * We think that Type 2 and Type 4 halftones, like
146*7dd7cddfSDavid du Colombier 	 * screens set by setcolorscreen, adapt automatically to
147*7dd7cddfSDavid du Colombier 	 * the device color space, so we need to mark them
148*7dd7cddfSDavid du Colombier 	 * with a different internal halftone type.
149*7dd7cddfSDavid du Colombier 	 */
150*7dd7cddfSDavid du Colombier 	int type = 0;
151*7dd7cddfSDavid du Colombier 
152*7dd7cddfSDavid du Colombier 	dict_int_param(op - 1, "HalftoneType", 1, 5, 0, &type);
153*7dd7cddfSDavid du Colombier 	pht->type =
154*7dd7cddfSDavid du Colombier 	    (type == 2 || type == 4 ? ht_type_multiple_colorscreen :
155*7dd7cddfSDavid du Colombier 	     ht_type_multiple);
156*7dd7cddfSDavid du Colombier 	pht->params.multiple.components = phtc;
157*7dd7cddfSDavid du Colombier 	pht->params.multiple.num_comp = count;
158*7dd7cddfSDavid du Colombier 	code = gs_sethalftone_prepare(igs, pht, pdht);
159*7dd7cddfSDavid du Colombier     }
160*7dd7cddfSDavid du Colombier     if (code >= 0)
161*7dd7cddfSDavid du Colombier 	for (j = 0, pc = phtc; j < count; j++, pc++) {
162*7dd7cddfSDavid du Colombier 	    if (pc->type == ht_type_spot) {
163*7dd7cddfSDavid du Colombier 		ref *pvalue;
164*7dd7cddfSDavid du Colombier 
165*7dd7cddfSDavid du Colombier 		dict_find_string(op, color_names[pc->cname], &pvalue);
166*7dd7cddfSDavid du Colombier 		code = dict_spot_results(i_ctx_p, pvalue, &pc->params.spot);
167*7dd7cddfSDavid du Colombier 		if (code < 0)
168*7dd7cddfSDavid du Colombier 		    break;
169*7dd7cddfSDavid du Colombier 	    }
170*7dd7cddfSDavid du Colombier 	}
171*7dd7cddfSDavid du Colombier     if (code >= 0) {
172*7dd7cddfSDavid du Colombier 	/*
173*7dd7cddfSDavid du Colombier 	 * Schedule the sampling of any Type 1 screens,
174*7dd7cddfSDavid du Colombier 	 * and any (Type 1 or Type 3) TransferFunctions.
175*7dd7cddfSDavid du Colombier 	 * Save the stack depths in case we have to back out.
176*7dd7cddfSDavid du Colombier 	 */
177*7dd7cddfSDavid du Colombier 	uint odepth = ref_stack_count(&o_stack);
178*7dd7cddfSDavid du Colombier 	ref odict, odict5;
179*7dd7cddfSDavid du Colombier 
180*7dd7cddfSDavid du Colombier 	odict = op[-1];
181*7dd7cddfSDavid du Colombier 	odict5 = *op;
182*7dd7cddfSDavid du Colombier 	pop(2);
183*7dd7cddfSDavid du Colombier 	op = osp;
184*7dd7cddfSDavid du Colombier 	esp += 5;
185*7dd7cddfSDavid du Colombier 	make_mark_estack(esp - 4, es_other, sethalftone_cleanup);
186*7dd7cddfSDavid du Colombier 	esp[-3] = odict;
187*7dd7cddfSDavid du Colombier 	make_istruct(esp - 2, 0, pht);
188*7dd7cddfSDavid du Colombier 	make_istruct(esp - 1, 0, pdht);
189*7dd7cddfSDavid du Colombier 	make_op_estack(esp, sethalftone_finish);
190*7dd7cddfSDavid du Colombier 	for (j = 0; j < count; j++) {
191*7dd7cddfSDavid du Colombier 	    gx_ht_order *porder =
192*7dd7cddfSDavid du Colombier 	    (pdht->components == 0 ? &pdht->order :
193*7dd7cddfSDavid du Colombier 	     &pdht->components[j].corder);
194*7dd7cddfSDavid du Colombier 
195*7dd7cddfSDavid du Colombier 	    switch (phtc[j].type) {
196*7dd7cddfSDavid du Colombier 		case ht_type_spot:
197*7dd7cddfSDavid du Colombier 		    code = zscreen_enum_init(i_ctx_p, porder,
198*7dd7cddfSDavid du Colombier 					     &phtc[j].params.spot.screen,
199*7dd7cddfSDavid du Colombier 					     &sprocs[j], 0, 0, mem);
200*7dd7cddfSDavid du Colombier 		    if (code < 0)
201*7dd7cddfSDavid du Colombier 			break;
202*7dd7cddfSDavid du Colombier 		    /* falls through */
203*7dd7cddfSDavid du Colombier 		case ht_type_threshold:
204*7dd7cddfSDavid du Colombier 		    if (!r_has_type(tprocs + j, t__invalid)) {
205*7dd7cddfSDavid du Colombier 			/* Schedule TransferFunction sampling. */
206*7dd7cddfSDavid du Colombier 			/****** check_xstack IS WRONG ******/
207*7dd7cddfSDavid du Colombier 			check_ostack(zcolor_remap_one_ostack);
208*7dd7cddfSDavid du Colombier 			check_estack(zcolor_remap_one_estack);
209*7dd7cddfSDavid du Colombier 			code = zcolor_remap_one(i_ctx_p, tprocs + j,
210*7dd7cddfSDavid du Colombier 						porder->transfer, igs,
211*7dd7cddfSDavid du Colombier 						zcolor_remap_one_finish);
212*7dd7cddfSDavid du Colombier 			op = osp;
213*7dd7cddfSDavid du Colombier 		    }
214*7dd7cddfSDavid du Colombier 		    break;
215*7dd7cddfSDavid du Colombier 		default:	/* not possible here, but to keep */
216*7dd7cddfSDavid du Colombier 		    /* the compilers happy.... */
217*7dd7cddfSDavid du Colombier 		    ;
218*7dd7cddfSDavid du Colombier 	    }
219*7dd7cddfSDavid du Colombier 	    if (code < 0) {	/* Restore the stack. */
220*7dd7cddfSDavid du Colombier 		ref_stack_pop_to(&o_stack, odepth);
221*7dd7cddfSDavid du Colombier 		ref_stack_pop_to(&e_stack, edepth);
222*7dd7cddfSDavid du Colombier 		op = osp;
223*7dd7cddfSDavid du Colombier 		op[-1] = odict;
224*7dd7cddfSDavid du Colombier 		*op = odict5;
225*7dd7cddfSDavid du Colombier 		break;
226*7dd7cddfSDavid du Colombier 	    }
227*7dd7cddfSDavid du Colombier 	    npop = 0;
228*7dd7cddfSDavid du Colombier 	}
229*7dd7cddfSDavid du Colombier     }
230*7dd7cddfSDavid du Colombier     if (code < 0) {
231*7dd7cddfSDavid du Colombier 	gs_free_object(mem, pdht, ".sethalftone5");
232*7dd7cddfSDavid du Colombier 	gs_free_object(mem, phtc, ".sethalftone5");
233*7dd7cddfSDavid du Colombier 	gs_free_object(mem, pht, ".sethalftone5");
234*7dd7cddfSDavid du Colombier 	return code;
235*7dd7cddfSDavid du Colombier     }
236*7dd7cddfSDavid du Colombier     pop(npop);
237*7dd7cddfSDavid du Colombier     return (ref_stack_count(&e_stack) > edepth ? o_push_estack : 0);
238*7dd7cddfSDavid du Colombier }
239*7dd7cddfSDavid du Colombier /* Install the halftone after sampling. */
240*7dd7cddfSDavid du Colombier private int
241*7dd7cddfSDavid du Colombier sethalftone_finish(i_ctx_t *i_ctx_p)
242*7dd7cddfSDavid du Colombier {
243*7dd7cddfSDavid du Colombier     gx_device_halftone *pdht = r_ptr(esp, gx_device_halftone);
244*7dd7cddfSDavid du Colombier     int code;
245*7dd7cddfSDavid du Colombier 
246*7dd7cddfSDavid du Colombier     if (pdht->components)
247*7dd7cddfSDavid du Colombier 	pdht->order = pdht->components[0].corder;
248*7dd7cddfSDavid du Colombier     code = gx_ht_install(igs, r_ptr(esp - 1, gs_halftone), pdht);
249*7dd7cddfSDavid du Colombier     if (code < 0)
250*7dd7cddfSDavid du Colombier 	return code;
251*7dd7cddfSDavid du Colombier     istate->halftone = esp[-2];
252*7dd7cddfSDavid du Colombier     esp -= 4;
253*7dd7cddfSDavid du Colombier     sethalftone_cleanup(i_ctx_p);
254*7dd7cddfSDavid du Colombier     return o_pop_estack;
255*7dd7cddfSDavid du Colombier }
256*7dd7cddfSDavid du Colombier /* Clean up after installing the halftone. */
257*7dd7cddfSDavid du Colombier private int
258*7dd7cddfSDavid du Colombier sethalftone_cleanup(i_ctx_t *i_ctx_p)
259*7dd7cddfSDavid du Colombier {
260*7dd7cddfSDavid du Colombier     gx_device_halftone *pdht = r_ptr(&esp[4], gx_device_halftone);
261*7dd7cddfSDavid du Colombier     gs_halftone *pht = r_ptr(&esp[3], gs_halftone);
262*7dd7cddfSDavid du Colombier 
263*7dd7cddfSDavid du Colombier     gs_free_object(pdht->rc.memory, pdht,
264*7dd7cddfSDavid du Colombier 		   "sethalftone_cleanup(device halftone)");
265*7dd7cddfSDavid du Colombier     gs_free_object(pht->rc.memory, pht,
266*7dd7cddfSDavid du Colombier 		   "sethalftone_cleanup(halftone)");
267*7dd7cddfSDavid du Colombier     return 0;
268*7dd7cddfSDavid du Colombier }
269*7dd7cddfSDavid du Colombier 
270*7dd7cddfSDavid du Colombier /* ------ Initialization procedure ------ */
271*7dd7cddfSDavid du Colombier 
272*7dd7cddfSDavid du Colombier const op_def zht2_l2_op_defs[] =
273*7dd7cddfSDavid du Colombier {
274*7dd7cddfSDavid du Colombier     op_def_begin_level2(),
275*7dd7cddfSDavid du Colombier     {"2.sethalftone5", zsethalftone5},
276*7dd7cddfSDavid du Colombier 		/* Internal operators */
277*7dd7cddfSDavid du Colombier     {"0%sethalftone_finish", sethalftone_finish},
278*7dd7cddfSDavid du Colombier     op_def_end(0)
279*7dd7cddfSDavid du Colombier };
280*7dd7cddfSDavid du Colombier 
281*7dd7cddfSDavid du Colombier /* ------ Internal routines ------ */
282*7dd7cddfSDavid du Colombier 
283*7dd7cddfSDavid du Colombier /* Extract frequency, angle, spot function, and accurate screens flag */
284*7dd7cddfSDavid du Colombier /* from a dictionary. */
285*7dd7cddfSDavid du Colombier private int
286*7dd7cddfSDavid du Colombier dict_spot_params(const ref * pdict, gs_spot_halftone * psp,
287*7dd7cddfSDavid du Colombier 		 ref * psproc, ref * ptproc)
288*7dd7cddfSDavid du Colombier {
289*7dd7cddfSDavid du Colombier     int code;
290*7dd7cddfSDavid du Colombier 
291*7dd7cddfSDavid du Colombier     check_dict_read(*pdict);
292*7dd7cddfSDavid du Colombier     if ((code = dict_float_param(pdict, "Frequency", 0.0,
293*7dd7cddfSDavid du Colombier 				 &psp->screen.frequency)) != 0 ||
294*7dd7cddfSDavid du Colombier 	(code = dict_float_param(pdict, "Angle", 0.0,
295*7dd7cddfSDavid du Colombier 				 &psp->screen.angle)) != 0 ||
296*7dd7cddfSDavid du Colombier       (code = dict_proc_param(pdict, "SpotFunction", psproc, false)) != 0 ||
297*7dd7cddfSDavid du Colombier 	(code = dict_bool_param(pdict, "AccurateScreens",
298*7dd7cddfSDavid du Colombier 				gs_currentaccuratescreens(),
299*7dd7cddfSDavid du Colombier 				&psp->accurate_screens)) < 0 ||
300*7dd7cddfSDavid du Colombier       (code = dict_proc_param(pdict, "TransferFunction", ptproc, false)) < 0
301*7dd7cddfSDavid du Colombier 	)
302*7dd7cddfSDavid du Colombier 	return (code < 0 ? code : e_undefined);
303*7dd7cddfSDavid du Colombier     psp->transfer = (code > 0 ? (gs_mapping_proc) 0 : gs_mapped_transfer);
304*7dd7cddfSDavid du Colombier     psp->transfer_closure.proc = 0;
305*7dd7cddfSDavid du Colombier     psp->transfer_closure.data = 0;
306*7dd7cddfSDavid du Colombier     return 0;
307*7dd7cddfSDavid du Colombier }
308*7dd7cddfSDavid du Colombier 
309*7dd7cddfSDavid du Colombier /* Set actual frequency and angle in a dictionary. */
310*7dd7cddfSDavid du Colombier private int
311*7dd7cddfSDavid du Colombier dict_real_result(i_ctx_t *i_ctx_p, ref * pdict, const char *kstr, floatp val)
312*7dd7cddfSDavid du Colombier {
313*7dd7cddfSDavid du Colombier     int code = 0;
314*7dd7cddfSDavid du Colombier     ref *ignore;
315*7dd7cddfSDavid du Colombier 
316*7dd7cddfSDavid du Colombier     if (dict_find_string(pdict, kstr, &ignore) > 0) {
317*7dd7cddfSDavid du Colombier 	ref rval;
318*7dd7cddfSDavid du Colombier 
319*7dd7cddfSDavid du Colombier 	check_dict_write(*pdict);
320*7dd7cddfSDavid du Colombier 	make_real(&rval, val);
321*7dd7cddfSDavid du Colombier 	code = idict_put_string(pdict, kstr, &rval);
322*7dd7cddfSDavid du Colombier     }
323*7dd7cddfSDavid du Colombier     return code;
324*7dd7cddfSDavid du Colombier }
325*7dd7cddfSDavid du Colombier private int
326*7dd7cddfSDavid du Colombier dict_spot_results(i_ctx_t *i_ctx_p, ref * pdict, const gs_spot_halftone * psp)
327*7dd7cddfSDavid du Colombier {
328*7dd7cddfSDavid du Colombier     int code;
329*7dd7cddfSDavid du Colombier 
330*7dd7cddfSDavid du Colombier     code = dict_real_result(i_ctx_p, pdict, "ActualFrequency",
331*7dd7cddfSDavid du Colombier 			    psp->screen.actual_frequency);
332*7dd7cddfSDavid du Colombier     if (code < 0)
333*7dd7cddfSDavid du Colombier 	return code;
334*7dd7cddfSDavid du Colombier     return dict_real_result(i_ctx_p, pdict, "ActualAngle",
335*7dd7cddfSDavid du Colombier 			    psp->screen.actual_angle);
336*7dd7cddfSDavid du Colombier }
337*7dd7cddfSDavid du Colombier 
338*7dd7cddfSDavid du Colombier /* Extract Width, Height, and TransferFunction from a dictionary. */
339*7dd7cddfSDavid du Colombier private int
340*7dd7cddfSDavid du Colombier dict_threshold_common_params(const ref * pdict,
341*7dd7cddfSDavid du Colombier 			     gs_threshold_halftone_common * ptp,
342*7dd7cddfSDavid du Colombier 			     ref **pptstring, ref *ptproc)
343*7dd7cddfSDavid du Colombier {
344*7dd7cddfSDavid du Colombier     int code;
345*7dd7cddfSDavid du Colombier 
346*7dd7cddfSDavid du Colombier     check_dict_read(*pdict);
347*7dd7cddfSDavid du Colombier     if ((code = dict_int_param(pdict, "Width", 1, 0x7fff, -1,
348*7dd7cddfSDavid du Colombier 			       &ptp->width)) < 0 ||
349*7dd7cddfSDavid du Colombier 	(code = dict_int_param(pdict, "Height", 1, 0x7fff, -1,
350*7dd7cddfSDavid du Colombier 			       &ptp->height)) < 0 ||
351*7dd7cddfSDavid du Colombier 	(code = dict_find_string(pdict, "Thresholds", pptstring)) <= 0 ||
352*7dd7cddfSDavid du Colombier       (code = dict_proc_param(pdict, "TransferFunction", ptproc, false)) < 0
353*7dd7cddfSDavid du Colombier 	)
354*7dd7cddfSDavid du Colombier 	return (code < 0 ? code : e_undefined);
355*7dd7cddfSDavid du Colombier     ptp->transfer_closure.proc = 0;
356*7dd7cddfSDavid du Colombier     ptp->transfer_closure.data = 0;
357*7dd7cddfSDavid du Colombier     return code;
358*7dd7cddfSDavid du Colombier }
359*7dd7cddfSDavid du Colombier 
360*7dd7cddfSDavid du Colombier /* Extract threshold common parameters + Thresholds. */
361*7dd7cddfSDavid du Colombier private int
362*7dd7cddfSDavid du Colombier dict_threshold_params(const ref * pdict, gs_threshold_halftone * ptp,
363*7dd7cddfSDavid du Colombier 		      ref * ptproc)
364*7dd7cddfSDavid du Colombier {
365*7dd7cddfSDavid du Colombier     ref *tstring;
366*7dd7cddfSDavid du Colombier     int code =
367*7dd7cddfSDavid du Colombier 	dict_threshold_common_params(pdict,
368*7dd7cddfSDavid du Colombier 				     (gs_threshold_halftone_common *)ptp,
369*7dd7cddfSDavid du Colombier 				     &tstring, ptproc);
370*7dd7cddfSDavid du Colombier 
371*7dd7cddfSDavid du Colombier     if (code < 0)
372*7dd7cddfSDavid du Colombier 	return code;
373*7dd7cddfSDavid du Colombier     check_read_type_only(*tstring, t_string);
374*7dd7cddfSDavid du Colombier     if (r_size(tstring) != (long)ptp->width * ptp->height)
375*7dd7cddfSDavid du Colombier 	return_error(e_rangecheck);
376*7dd7cddfSDavid du Colombier     ptp->thresholds.data = tstring->value.const_bytes;
377*7dd7cddfSDavid du Colombier     ptp->thresholds.size = r_size(tstring);
378*7dd7cddfSDavid du Colombier     ptp->transfer = (code > 0 ? (gs_mapping_proc) 0 : gs_mapped_transfer);
379*7dd7cddfSDavid du Colombier     return 0;
380*7dd7cddfSDavid du Colombier }
381*7dd7cddfSDavid du Colombier 
382*7dd7cddfSDavid du Colombier /* Extract threshold common parameters + Thresholds, Width2, Height2, */
383*7dd7cddfSDavid du Colombier /* BitsPerSample. */
384*7dd7cddfSDavid du Colombier private int
385*7dd7cddfSDavid du Colombier dict_threshold2_params(const ref * pdict, gs_threshold2_halftone * ptp,
386*7dd7cddfSDavid du Colombier 		       ref * ptproc, gs_memory_t *mem)
387*7dd7cddfSDavid du Colombier {
388*7dd7cddfSDavid du Colombier     ref *tstring;
389*7dd7cddfSDavid du Colombier     int code =
390*7dd7cddfSDavid du Colombier 	dict_threshold_common_params(pdict,
391*7dd7cddfSDavid du Colombier 				     (gs_threshold_halftone_common *)ptp,
392*7dd7cddfSDavid du Colombier 				     &tstring, ptproc);
393*7dd7cddfSDavid du Colombier     int bps;
394*7dd7cddfSDavid du Colombier     uint size;
395*7dd7cddfSDavid du Colombier     int cw2, ch2;
396*7dd7cddfSDavid du Colombier 
397*7dd7cddfSDavid du Colombier     if (code < 0 ||
398*7dd7cddfSDavid du Colombier 	(code = cw2 = dict_int_param(pdict, "Width2", 0, 0x7fff, 0,
399*7dd7cddfSDavid du Colombier 				     &ptp->width2)) < 0 ||
400*7dd7cddfSDavid du Colombier 	(code = ch2 = dict_int_param(pdict, "Height2", 0, 0x7fff, 0,
401*7dd7cddfSDavid du Colombier 				     &ptp->height2)) < 0 ||
402*7dd7cddfSDavid du Colombier 	(code = dict_int_param(pdict, "BitsPerSample", 8, 16, -1, &bps)) < 0
403*7dd7cddfSDavid du Colombier 	)
404*7dd7cddfSDavid du Colombier 	return code;
405*7dd7cddfSDavid du Colombier     if ((bps != 8 && bps != 16) || cw2 != ch2 ||
406*7dd7cddfSDavid du Colombier 	(!cw2 && (ptp->width2 == 0 || ptp->height2 == 0))
407*7dd7cddfSDavid du Colombier 	)
408*7dd7cddfSDavid du Colombier 	return_error(e_rangecheck);
409*7dd7cddfSDavid du Colombier     ptp->bytes_per_sample = bps / 8;
410*7dd7cddfSDavid du Colombier     switch (r_type(tstring)) {
411*7dd7cddfSDavid du Colombier     case t_string:
412*7dd7cddfSDavid du Colombier 	size = r_size(tstring);
413*7dd7cddfSDavid du Colombier 	gs_bytestring_from_string(&ptp->thresholds, tstring->value.const_bytes,
414*7dd7cddfSDavid du Colombier 				  size);
415*7dd7cddfSDavid du Colombier 	break;
416*7dd7cddfSDavid du Colombier     case t_astruct:
417*7dd7cddfSDavid du Colombier 	if (gs_object_type(mem, tstring->value.pstruct) != &st_bytes)
418*7dd7cddfSDavid du Colombier 	    return_error(e_typecheck);
419*7dd7cddfSDavid du Colombier 	size = gs_object_size(mem, tstring->value.pstruct);
420*7dd7cddfSDavid du Colombier 	gs_bytestring_from_bytes(&ptp->thresholds, r_ptr(tstring, byte),
421*7dd7cddfSDavid du Colombier 				 0, size);
422*7dd7cddfSDavid du Colombier 	break;
423*7dd7cddfSDavid du Colombier     default:
424*7dd7cddfSDavid du Colombier 	return_error(e_typecheck);
425*7dd7cddfSDavid du Colombier     }
426*7dd7cddfSDavid du Colombier     check_read(*tstring);
427*7dd7cddfSDavid du Colombier     if (size != (ptp->width * ptp->height + ptp->width2 * ptp->height2) *
428*7dd7cddfSDavid du Colombier 	ptp->bytes_per_sample)
429*7dd7cddfSDavid du Colombier 	return_error(e_rangecheck);
430*7dd7cddfSDavid du Colombier     return 0;
431*7dd7cddfSDavid du Colombier }
432