xref: /plan9/sys/src/cmd/gs/src/zht2.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
17dd7cddfSDavid du Colombier /* Copyright (C) 1992, 1995, 1996, 1997, 1998, 1999 Aladdin Enterprises.  All rights reserved.
27dd7cddfSDavid du Colombier 
3*593dc095SDavid du Colombier   This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier   implied.
57dd7cddfSDavid 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.
97dd7cddfSDavid 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.
157dd7cddfSDavid du Colombier */
167dd7cddfSDavid du Colombier 
17*593dc095SDavid du Colombier /* $Id: zht2.c,v 1.14 2005/10/11 10:04:28 leonardo Exp $ */
187dd7cddfSDavid du Colombier /* Level 2 sethalftone operator */
197dd7cddfSDavid du Colombier #include "ghost.h"
207dd7cddfSDavid du Colombier #include "oper.h"
217dd7cddfSDavid du Colombier #include "gsstruct.h"
227dd7cddfSDavid du Colombier #include "gxdevice.h"		/* for gzht.h */
237dd7cddfSDavid du Colombier #include "gzht.h"
247dd7cddfSDavid du Colombier #include "estack.h"
257dd7cddfSDavid du Colombier #include "ialloc.h"
267dd7cddfSDavid du Colombier #include "iddict.h"
277dd7cddfSDavid du Colombier #include "idparam.h"
287dd7cddfSDavid du Colombier #include "igstate.h"
297dd7cddfSDavid du Colombier #include "icolor.h"
307dd7cddfSDavid du Colombier #include "iht.h"
317dd7cddfSDavid du Colombier #include "store.h"
32*593dc095SDavid du Colombier #include "iname.h"
33*593dc095SDavid du Colombier #include "zht2.h"
347dd7cddfSDavid du Colombier 
357dd7cddfSDavid du Colombier /* Forward references */
36*593dc095SDavid du Colombier private int dict_spot_params(const ref *, gs_spot_halftone *, ref *, ref *);
37*593dc095SDavid du Colombier private int dict_spot_results(i_ctx_t *, ref *, const gs_spot_halftone *);
38*593dc095SDavid du Colombier private int dict_threshold_params(const ref *, gs_threshold_halftone *,
39*593dc095SDavid du Colombier 				  ref *);
40*593dc095SDavid du Colombier private int dict_threshold2_params(const ref *, gs_threshold2_halftone *,
41*593dc095SDavid du Colombier 				   ref *, gs_memory_t *);
42*593dc095SDavid du Colombier 
43*593dc095SDavid du Colombier /*
44*593dc095SDavid du Colombier  * This routine translates a gs_separation_name value into a character string
45*593dc095SDavid du Colombier  * pointer and a string length.
46*593dc095SDavid du Colombier  */
47*593dc095SDavid du Colombier int
gs_get_colorname_string(const gs_memory_t * mem,gs_separation_name colorname_index,unsigned char ** ppstr,unsigned int * pname_size)48*593dc095SDavid du Colombier gs_get_colorname_string(const gs_memory_t *mem, gs_separation_name colorname_index,
49*593dc095SDavid du Colombier 			unsigned char **ppstr, unsigned int *pname_size)
50*593dc095SDavid du Colombier {
51*593dc095SDavid du Colombier     ref nref;
52*593dc095SDavid du Colombier 
53*593dc095SDavid du Colombier     name_index_ref(mem, colorname_index, &nref);
54*593dc095SDavid du Colombier     name_string_ref(mem, &nref, &nref);
55*593dc095SDavid du Colombier     return obj_string_data(mem, &nref, (const unsigned char**) ppstr, pname_size);
56*593dc095SDavid du Colombier }
577dd7cddfSDavid du Colombier 
587dd7cddfSDavid du Colombier /* Dummy spot function */
597dd7cddfSDavid du Colombier private float
spot1_dummy(floatp x,floatp y)607dd7cddfSDavid du Colombier spot1_dummy(floatp x, floatp y)
617dd7cddfSDavid du Colombier {
627dd7cddfSDavid du Colombier     return (x + y) / 2;
637dd7cddfSDavid du Colombier }
647dd7cddfSDavid du Colombier 
657dd7cddfSDavid du Colombier /* <dict> <dict5> .sethalftone5 - */
66*593dc095SDavid du Colombier private int sethalftone_finish(i_ctx_t *);
67*593dc095SDavid du Colombier private int sethalftone_cleanup(i_ctx_t *);
687dd7cddfSDavid du Colombier private int
zsethalftone5(i_ctx_t * i_ctx_p)697dd7cddfSDavid du Colombier zsethalftone5(i_ctx_t *i_ctx_p)
707dd7cddfSDavid du Colombier {
717dd7cddfSDavid du Colombier     os_ptr op = osp;
727dd7cddfSDavid du Colombier     uint count;
737dd7cddfSDavid du Colombier     gs_halftone_component *phtc;
747dd7cddfSDavid du Colombier     gs_halftone_component *pc;
757dd7cddfSDavid du Colombier     int code = 0;
76*593dc095SDavid du Colombier     int j;
777dd7cddfSDavid du Colombier     gs_halftone *pht;
787dd7cddfSDavid du Colombier     gx_device_halftone *pdht;
79*593dc095SDavid du Colombier     ref sprocs[GS_CLIENT_COLOR_MAX_COMPONENTS + 1];
80*593dc095SDavid du Colombier     ref tprocs[GS_CLIENT_COLOR_MAX_COMPONENTS + 1];
817dd7cddfSDavid du Colombier     gs_memory_t *mem;
827dd7cddfSDavid du Colombier     uint edepth = ref_stack_count(&e_stack);
837dd7cddfSDavid du Colombier     int npop = 2;
84*593dc095SDavid du Colombier     int dict_enum = dict_first(op);
85*593dc095SDavid du Colombier     ref rvalue[2];
86*593dc095SDavid du Colombier     int cname, colorant_number;
87*593dc095SDavid du Colombier     byte * pname;
88*593dc095SDavid du Colombier     uint name_size;
89*593dc095SDavid du Colombier     int halftonetype, type = 0;
90*593dc095SDavid du Colombier     gs_state *pgs = igs;
91*593dc095SDavid du Colombier     int space_index = r_space_index(op - 1);
92*593dc095SDavid du Colombier 
93*593dc095SDavid du Colombier     mem = (gs_memory_t *) idmemory->spaces_indexed[space_index];
947dd7cddfSDavid du Colombier 
957dd7cddfSDavid du Colombier     check_type(*op, t_dictionary);
967dd7cddfSDavid du Colombier     check_dict_read(*op);
977dd7cddfSDavid du Colombier     check_type(op[-1], t_dictionary);
987dd7cddfSDavid du Colombier     check_dict_read(op[-1]);
997dd7cddfSDavid du Colombier 
100*593dc095SDavid du Colombier     /*
101*593dc095SDavid du Colombier      * We think that Type 2 and Type 4 halftones, like
102*593dc095SDavid du Colombier      * screens set by setcolorscreen, adapt automatically to
103*593dc095SDavid du Colombier      * the device color space, so we need to mark them
104*593dc095SDavid du Colombier      * with a different internal halftone type.
105*593dc095SDavid du Colombier      */
106*593dc095SDavid du Colombier     dict_int_param(op - 1, "HalftoneType", 1, 5, 0, &type);
107*593dc095SDavid du Colombier     halftonetype = (type == 2 || type == 4)
108*593dc095SDavid du Colombier     			? ht_type_multiple_colorscreen
109*593dc095SDavid du Colombier 			: ht_type_multiple;
110*593dc095SDavid du Colombier 
111*593dc095SDavid du Colombier     /* Count how many components that we will actually use. */
112*593dc095SDavid du Colombier 
113*593dc095SDavid du Colombier     for (count = 0; ;) {
114*593dc095SDavid du Colombier 	bool have_default = false;
115*593dc095SDavid du Colombier 
116*593dc095SDavid du Colombier 	/* Move to next element in the dictionary */
117*593dc095SDavid du Colombier 	if ((dict_enum = dict_next(op, dict_enum, rvalue)) == -1)
118*593dc095SDavid du Colombier 	    break;
119*593dc095SDavid du Colombier 	/*
120*593dc095SDavid du Colombier 	 * Verify that we have a valid component.  We may have a
121*593dc095SDavid du Colombier 	 * /HalfToneType entry.
122*593dc095SDavid du Colombier 	 */
123*593dc095SDavid du Colombier   	if (!r_has_type(&rvalue[1], t_dictionary))
124*593dc095SDavid du Colombier 	    continue;
125*593dc095SDavid du Colombier 
126*593dc095SDavid du Colombier 	/* Get the name of the component  verify that we will use it. */
127*593dc095SDavid du Colombier 	cname = name_index(mem, &rvalue[0]);
128*593dc095SDavid du Colombier 	code = gs_get_colorname_string(mem, cname, &pname, &name_size);
129*593dc095SDavid du Colombier 	if (code < 0)
130*593dc095SDavid du Colombier 	    break;
131*593dc095SDavid du Colombier 	colorant_number = gs_cname_to_colorant_number(pgs, pname, name_size,
132*593dc095SDavid du Colombier 						halftonetype);
133*593dc095SDavid du Colombier 	if (colorant_number < 0)
134*593dc095SDavid du Colombier 	    continue;
135*593dc095SDavid du Colombier 	else if (colorant_number == GX_DEVICE_COLOR_MAX_COMPONENTS) {
136*593dc095SDavid du Colombier 	    /* If here then we have the "Default" component */
137*593dc095SDavid du Colombier 	    if (have_default)
138*593dc095SDavid du Colombier 		return_error(e_rangecheck);
139*593dc095SDavid du Colombier 	    have_default = true;
1407dd7cddfSDavid du Colombier 	}
141*593dc095SDavid du Colombier 
142*593dc095SDavid du Colombier 	count++;
143*593dc095SDavid du Colombier 	/*
144*593dc095SDavid du Colombier 	 * Check to see if we have already reached the legal number of
145*593dc095SDavid du Colombier 	 * components.
146*593dc095SDavid du Colombier 	 */
147*593dc095SDavid du Colombier 	if (count > GS_CLIENT_COLOR_MAX_COMPONENTS + 1) {
148*593dc095SDavid du Colombier 	    code = gs_note_error(e_rangecheck);
149*593dc095SDavid du Colombier 	    break;
150*593dc095SDavid du Colombier         }
151*593dc095SDavid du Colombier     }
152*593dc095SDavid du Colombier 
1537dd7cddfSDavid du Colombier     check_estack(5);		/* for sampling Type 1 screens */
154*593dc095SDavid du Colombier     refset_null(sprocs, count);
155*593dc095SDavid du Colombier     refset_null(tprocs, count);
1567dd7cddfSDavid du Colombier     rc_alloc_struct_0(pht, gs_halftone, &st_halftone,
1577dd7cddfSDavid du Colombier 		      imemory, pht = 0, ".sethalftone5");
1587dd7cddfSDavid du Colombier     phtc = gs_alloc_struct_array(mem, count, gs_halftone_component,
1597dd7cddfSDavid du Colombier 				 &st_ht_component_element,
1607dd7cddfSDavid du Colombier 				 ".sethalftone5");
1617dd7cddfSDavid du Colombier     rc_alloc_struct_0(pdht, gx_device_halftone, &st_device_halftone,
1627dd7cddfSDavid du Colombier 		      imemory, pdht = 0, ".sethalftone5");
163*593dc095SDavid du Colombier     if (pht == 0 || phtc == 0 || pdht == 0) {
164*593dc095SDavid du Colombier 	j = 0; /* Quiet the compiler:
165*593dc095SDavid du Colombier 	          gs_note_error isn't necessarily identity,
166*593dc095SDavid du Colombier 		  so j could be left ununitialized. */
1677dd7cddfSDavid du Colombier 	code = gs_note_error(e_VMerror);
168*593dc095SDavid du Colombier     } else {
169*593dc095SDavid du Colombier         dict_enum = dict_first(op);
170*593dc095SDavid du Colombier 	for (j = 0, pc = phtc; ;) {
1717dd7cddfSDavid du Colombier 	    int type;
1727dd7cddfSDavid du Colombier 
173*593dc095SDavid du Colombier 	    /* Move to next element in the dictionary */
174*593dc095SDavid du Colombier 	    if ((dict_enum = dict_next(op, dict_enum, rvalue)) == -1)
175*593dc095SDavid du Colombier 	        break;
176*593dc095SDavid du Colombier 	    /*
177*593dc095SDavid du Colombier 	     * Verify that we have a valid component.  We may have a
178*593dc095SDavid du Colombier 	     * /HalfToneType entry.
179*593dc095SDavid du Colombier 	     */
180*593dc095SDavid du Colombier   	    if (!r_has_type(&rvalue[1], t_dictionary))
181*593dc095SDavid du Colombier 		continue;
182*593dc095SDavid du Colombier 
183*593dc095SDavid du Colombier 	    /* Get the name of the component */
184*593dc095SDavid du Colombier 	    cname = name_index(mem, &rvalue[0]);
185*593dc095SDavid du Colombier 	    code = gs_get_colorname_string(mem, cname, &pname, &name_size);
186*593dc095SDavid du Colombier 	    if (code < 0)
187*593dc095SDavid du Colombier 	        break;
188*593dc095SDavid du Colombier 	    colorant_number = gs_cname_to_colorant_number(pgs, pname, name_size,
189*593dc095SDavid du Colombier 						halftonetype);
190*593dc095SDavid du Colombier 	    if (colorant_number < 0)
191*593dc095SDavid du Colombier 		continue;		/* Do not use this component */
192*593dc095SDavid du Colombier 	    pc->cname = cname;
193*593dc095SDavid du Colombier 	    pc->comp_number = colorant_number;
194*593dc095SDavid du Colombier 
195*593dc095SDavid du Colombier 	    /* Now process the component dictionary */
196*593dc095SDavid du Colombier 	    check_dict_read(rvalue[1]);
197*593dc095SDavid du Colombier 	    if (dict_int_param(&rvalue[1], "HalftoneType", 1, 7, 0, &type) < 0) {
1987dd7cddfSDavid du Colombier 		code = gs_note_error(e_typecheck);
1997dd7cddfSDavid du Colombier 		break;
2007dd7cddfSDavid du Colombier 	    }
2017dd7cddfSDavid du Colombier 	    switch (type) {
2027dd7cddfSDavid du Colombier 		default:
2037dd7cddfSDavid du Colombier 		    code = gs_note_error(e_rangecheck);
2047dd7cddfSDavid du Colombier 		    break;
2057dd7cddfSDavid du Colombier 		case 1:
206*593dc095SDavid du Colombier 		    code = dict_spot_params(&rvalue[1], &pc->params.spot,
207*593dc095SDavid du Colombier 		    				sprocs + j, tprocs + j);
2087dd7cddfSDavid du Colombier 		    pc->params.spot.screen.spot_function = spot1_dummy;
2097dd7cddfSDavid du Colombier 		    pc->type = ht_type_spot;
2107dd7cddfSDavid du Colombier 		    break;
2117dd7cddfSDavid du Colombier 		case 3:
212*593dc095SDavid du Colombier 		    code = dict_threshold_params(&rvalue[1], &pc->params.threshold,
213*593dc095SDavid du Colombier 		    					tprocs + j);
2147dd7cddfSDavid du Colombier 		    pc->type = ht_type_threshold;
2157dd7cddfSDavid du Colombier 		    break;
2167dd7cddfSDavid du Colombier 		case 7:
217*593dc095SDavid du Colombier 		    code = dict_threshold2_params(&rvalue[1], &pc->params.threshold2,
218*593dc095SDavid du Colombier 		    					tprocs + j, imemory);
2197dd7cddfSDavid du Colombier 		    pc->type = ht_type_threshold2;
2207dd7cddfSDavid du Colombier 		    break;
2217dd7cddfSDavid du Colombier 	    }
2227dd7cddfSDavid du Colombier 	    if (code < 0)
2237dd7cddfSDavid du Colombier 		break;
224*593dc095SDavid du Colombier 	    pc++;
225*593dc095SDavid du Colombier 	    j++;
2267dd7cddfSDavid du Colombier 	}
2277dd7cddfSDavid du Colombier     }
2287dd7cddfSDavid du Colombier     if (code >= 0) {
229*593dc095SDavid du Colombier 	pht->type = halftonetype;
2307dd7cddfSDavid du Colombier 	pht->params.multiple.components = phtc;
231*593dc095SDavid du Colombier 	pht->params.multiple.num_comp = j;
232*593dc095SDavid du Colombier 	pht->params.multiple.get_colorname_string = gs_get_colorname_string;
2337dd7cddfSDavid du Colombier 	code = gs_sethalftone_prepare(igs, pht, pdht);
2347dd7cddfSDavid du Colombier     }
235*593dc095SDavid du Colombier     if (code >= 0) {
236*593dc095SDavid du Colombier 	/*
237*593dc095SDavid du Colombier 	 * Put the actual frequency and angle in the spot function component dictionaries.
238*593dc095SDavid du Colombier 	 */
239*593dc095SDavid du Colombier 	dict_enum = dict_first(op);
240*593dc095SDavid du Colombier 	for (pc = phtc; ; ) {
241*593dc095SDavid du Colombier 	    /* Move to next element in the dictionary */
242*593dc095SDavid du Colombier 	    if ((dict_enum = dict_next(op, dict_enum, rvalue)) == -1)
243*593dc095SDavid du Colombier 		break;
2447dd7cddfSDavid du Colombier 
245*593dc095SDavid du Colombier 	    /* Verify that we have a valid component */
246*593dc095SDavid du Colombier 	    if (!r_has_type(&rvalue[1], t_dictionary))
247*593dc095SDavid du Colombier 		continue;
248*593dc095SDavid du Colombier 
249*593dc095SDavid du Colombier 	    /* Get the name of the component and verify that we will use it. */
250*593dc095SDavid du Colombier 	    cname = name_index(mem, &rvalue[0]);
251*593dc095SDavid du Colombier 	    code = gs_get_colorname_string(mem, cname, &pname, &name_size);
2527dd7cddfSDavid du Colombier 	    if (code < 0)
2537dd7cddfSDavid du Colombier 	        break;
254*593dc095SDavid du Colombier 	    colorant_number = gs_cname_to_colorant_number(pgs, pname, name_size,
255*593dc095SDavid du Colombier 						halftonetype);
256*593dc095SDavid du Colombier 	    if (colorant_number < 0)
257*593dc095SDavid du Colombier 		continue;
258*593dc095SDavid du Colombier 
259*593dc095SDavid du Colombier 	    if (pc->type == ht_type_spot) {
260*593dc095SDavid du Colombier 		code = dict_spot_results(i_ctx_p, &rvalue[1], &pc->params.spot);
261*593dc095SDavid du Colombier 		if (code < 0)
262*593dc095SDavid du Colombier 		    break;
263*593dc095SDavid du Colombier 	    }
264*593dc095SDavid du Colombier 	    pc++;
2657dd7cddfSDavid du Colombier 	}
2667dd7cddfSDavid du Colombier     }
2677dd7cddfSDavid du Colombier     if (code >= 0) {
2687dd7cddfSDavid du Colombier 	/*
2697dd7cddfSDavid du Colombier 	 * Schedule the sampling of any Type 1 screens,
2707dd7cddfSDavid du Colombier 	 * and any (Type 1 or Type 3) TransferFunctions.
2717dd7cddfSDavid du Colombier 	 * Save the stack depths in case we have to back out.
2727dd7cddfSDavid du Colombier 	 */
2737dd7cddfSDavid du Colombier 	uint odepth = ref_stack_count(&o_stack);
2747dd7cddfSDavid du Colombier 	ref odict, odict5;
2757dd7cddfSDavid du Colombier 
2767dd7cddfSDavid du Colombier 	odict = op[-1];
2777dd7cddfSDavid du Colombier 	odict5 = *op;
2787dd7cddfSDavid du Colombier 	pop(2);
2797dd7cddfSDavid du Colombier 	op = osp;
2807dd7cddfSDavid du Colombier 	esp += 5;
2817dd7cddfSDavid du Colombier 	make_mark_estack(esp - 4, es_other, sethalftone_cleanup);
2827dd7cddfSDavid du Colombier 	esp[-3] = odict;
2837dd7cddfSDavid du Colombier 	make_istruct(esp - 2, 0, pht);
2847dd7cddfSDavid du Colombier 	make_istruct(esp - 1, 0, pdht);
2857dd7cddfSDavid du Colombier 	make_op_estack(esp, sethalftone_finish);
2867dd7cddfSDavid du Colombier 	for (j = 0; j < count; j++) {
287*593dc095SDavid du Colombier 	    gx_ht_order *porder = NULL;
2887dd7cddfSDavid du Colombier 
289*593dc095SDavid du Colombier 	    if (pdht->components == 0)
290*593dc095SDavid du Colombier 		porder = &pdht->order;
291*593dc095SDavid du Colombier 	    else {
292*593dc095SDavid du Colombier 		/* Find the component in pdht that matches component j in
293*593dc095SDavid du Colombier 		   the pht; gs_sethalftone_prepare() may permute these. */
294*593dc095SDavid du Colombier 		int k;
295*593dc095SDavid du Colombier 		int comp_number = phtc[j].comp_number;
296*593dc095SDavid du Colombier 		for (k = 0; k < count; k++) {
297*593dc095SDavid du Colombier 		    if (pdht->components[k].comp_number == comp_number) {
298*593dc095SDavid du Colombier 			porder = &pdht->components[k].corder;
299*593dc095SDavid du Colombier 			break;
300*593dc095SDavid du Colombier 		    }
301*593dc095SDavid du Colombier 		}
302*593dc095SDavid du Colombier 	    }
3037dd7cddfSDavid du Colombier 	    switch (phtc[j].type) {
3047dd7cddfSDavid du Colombier 	    case ht_type_spot:
3057dd7cddfSDavid du Colombier 		code = zscreen_enum_init(i_ctx_p, porder,
3067dd7cddfSDavid du Colombier 					 &phtc[j].params.spot.screen,
307*593dc095SDavid du Colombier 					 &sprocs[j], 0, 0, space_index);
3087dd7cddfSDavid du Colombier 		if (code < 0)
3097dd7cddfSDavid du Colombier 		    break;
3107dd7cddfSDavid du Colombier 		/* falls through */
3117dd7cddfSDavid du Colombier 	    case ht_type_threshold:
3127dd7cddfSDavid du Colombier 		if (!r_has_type(tprocs + j, t__invalid)) {
3137dd7cddfSDavid du Colombier 		    /* Schedule TransferFunction sampling. */
3147dd7cddfSDavid du Colombier 		    /****** check_xstack IS WRONG ******/
3157dd7cddfSDavid du Colombier 		    check_ostack(zcolor_remap_one_ostack);
3167dd7cddfSDavid du Colombier 		    check_estack(zcolor_remap_one_estack);
3177dd7cddfSDavid du Colombier 		    code = zcolor_remap_one(i_ctx_p, tprocs + j,
3187dd7cddfSDavid du Colombier 					    porder->transfer, igs,
3197dd7cddfSDavid du Colombier 					    zcolor_remap_one_finish);
3207dd7cddfSDavid du Colombier 		    op = osp;
3217dd7cddfSDavid du Colombier 		}
3227dd7cddfSDavid du Colombier 		break;
3237dd7cddfSDavid du Colombier 	    default:	/* not possible here, but to keep */
3247dd7cddfSDavid du Colombier 				/* the compilers happy.... */
3257dd7cddfSDavid du Colombier 		;
3267dd7cddfSDavid du Colombier 	    }
3277dd7cddfSDavid du Colombier 	    if (code < 0) {	/* Restore the stack. */
3287dd7cddfSDavid du Colombier 		ref_stack_pop_to(&o_stack, odepth);
3297dd7cddfSDavid du Colombier 		ref_stack_pop_to(&e_stack, edepth);
3307dd7cddfSDavid du Colombier 		op = osp;
3317dd7cddfSDavid du Colombier 		op[-1] = odict;
3327dd7cddfSDavid du Colombier 		*op = odict5;
3337dd7cddfSDavid du Colombier 		break;
3347dd7cddfSDavid du Colombier 	    }
3357dd7cddfSDavid du Colombier 	    npop = 0;
3367dd7cddfSDavid du Colombier 	}
3377dd7cddfSDavid du Colombier     }
3387dd7cddfSDavid du Colombier     if (code < 0) {
3397dd7cddfSDavid du Colombier 	gs_free_object(mem, pdht, ".sethalftone5");
3407dd7cddfSDavid du Colombier 	gs_free_object(mem, phtc, ".sethalftone5");
3417dd7cddfSDavid du Colombier 	gs_free_object(mem, pht, ".sethalftone5");
3427dd7cddfSDavid du Colombier 	return code;
3437dd7cddfSDavid du Colombier     }
3447dd7cddfSDavid du Colombier     pop(npop);
3457dd7cddfSDavid du Colombier     return (ref_stack_count(&e_stack) > edepth ? o_push_estack : 0);
3467dd7cddfSDavid du Colombier }
347*593dc095SDavid du Colombier 
3487dd7cddfSDavid du Colombier /* Install the halftone after sampling. */
3497dd7cddfSDavid du Colombier private int
sethalftone_finish(i_ctx_t * i_ctx_p)3507dd7cddfSDavid du Colombier sethalftone_finish(i_ctx_t *i_ctx_p)
3517dd7cddfSDavid du Colombier {
3527dd7cddfSDavid du Colombier     gx_device_halftone *pdht = r_ptr(esp, gx_device_halftone);
3537dd7cddfSDavid du Colombier     int code;
3547dd7cddfSDavid du Colombier 
3557dd7cddfSDavid du Colombier     if (pdht->components)
3567dd7cddfSDavid du Colombier 	pdht->order = pdht->components[0].corder;
3577dd7cddfSDavid du Colombier     code = gx_ht_install(igs, r_ptr(esp - 1, gs_halftone), pdht);
3587dd7cddfSDavid du Colombier     if (code < 0)
3597dd7cddfSDavid du Colombier 	return code;
3607dd7cddfSDavid du Colombier     istate->halftone = esp[-2];
3617dd7cddfSDavid du Colombier     esp -= 4;
3627dd7cddfSDavid du Colombier     sethalftone_cleanup(i_ctx_p);
3637dd7cddfSDavid du Colombier     return o_pop_estack;
3647dd7cddfSDavid du Colombier }
3657dd7cddfSDavid du Colombier /* Clean up after installing the halftone. */
3667dd7cddfSDavid du Colombier private int
sethalftone_cleanup(i_ctx_t * i_ctx_p)3677dd7cddfSDavid du Colombier sethalftone_cleanup(i_ctx_t *i_ctx_p)
3687dd7cddfSDavid du Colombier {
3697dd7cddfSDavid du Colombier     gx_device_halftone *pdht = r_ptr(&esp[4], gx_device_halftone);
3707dd7cddfSDavid du Colombier     gs_halftone *pht = r_ptr(&esp[3], gs_halftone);
3717dd7cddfSDavid du Colombier 
3727dd7cddfSDavid du Colombier     gs_free_object(pdht->rc.memory, pdht,
3737dd7cddfSDavid du Colombier 		   "sethalftone_cleanup(device halftone)");
3747dd7cddfSDavid du Colombier     gs_free_object(pht->rc.memory, pht,
3757dd7cddfSDavid du Colombier 		   "sethalftone_cleanup(halftone)");
3767dd7cddfSDavid du Colombier     return 0;
3777dd7cddfSDavid du Colombier }
3787dd7cddfSDavid du Colombier 
3797dd7cddfSDavid du Colombier /* ------ Initialization procedure ------ */
3807dd7cddfSDavid du Colombier 
3817dd7cddfSDavid du Colombier const op_def zht2_l2_op_defs[] =
3827dd7cddfSDavid du Colombier {
3837dd7cddfSDavid du Colombier     op_def_begin_level2(),
3847dd7cddfSDavid du Colombier     {"2.sethalftone5", zsethalftone5},
3857dd7cddfSDavid du Colombier 		/* Internal operators */
3867dd7cddfSDavid du Colombier     {"0%sethalftone_finish", sethalftone_finish},
3877dd7cddfSDavid du Colombier     op_def_end(0)
3887dd7cddfSDavid du Colombier };
3897dd7cddfSDavid du Colombier 
3907dd7cddfSDavid du Colombier /* ------ Internal routines ------ */
3917dd7cddfSDavid du Colombier 
3927dd7cddfSDavid du Colombier /* Extract frequency, angle, spot function, and accurate screens flag */
3937dd7cddfSDavid du Colombier /* from a dictionary. */
3947dd7cddfSDavid du Colombier private int
dict_spot_params(const ref * pdict,gs_spot_halftone * psp,ref * psproc,ref * ptproc)3957dd7cddfSDavid du Colombier dict_spot_params(const ref * pdict, gs_spot_halftone * psp,
3967dd7cddfSDavid du Colombier 		 ref * psproc, ref * ptproc)
3977dd7cddfSDavid du Colombier {
3987dd7cddfSDavid du Colombier     int code;
3997dd7cddfSDavid du Colombier 
4007dd7cddfSDavid du Colombier     check_dict_read(*pdict);
4017dd7cddfSDavid du Colombier     if ((code = dict_float_param(pdict, "Frequency", 0.0,
4027dd7cddfSDavid du Colombier 				 &psp->screen.frequency)) != 0 ||
4037dd7cddfSDavid du Colombier 	(code = dict_float_param(pdict, "Angle", 0.0,
4047dd7cddfSDavid du Colombier 				 &psp->screen.angle)) != 0 ||
4057dd7cddfSDavid du Colombier       (code = dict_proc_param(pdict, "SpotFunction", psproc, false)) != 0 ||
4067dd7cddfSDavid du Colombier 	(code = dict_bool_param(pdict, "AccurateScreens",
4077dd7cddfSDavid du Colombier 				gs_currentaccuratescreens(),
4087dd7cddfSDavid du Colombier 				&psp->accurate_screens)) < 0 ||
4097dd7cddfSDavid du Colombier       (code = dict_proc_param(pdict, "TransferFunction", ptproc, false)) < 0
4107dd7cddfSDavid du Colombier 	)
4117dd7cddfSDavid du Colombier 	return (code < 0 ? code : e_undefined);
4127dd7cddfSDavid du Colombier     psp->transfer = (code > 0 ? (gs_mapping_proc) 0 : gs_mapped_transfer);
4137dd7cddfSDavid du Colombier     psp->transfer_closure.proc = 0;
4147dd7cddfSDavid du Colombier     psp->transfer_closure.data = 0;
4157dd7cddfSDavid du Colombier     return 0;
4167dd7cddfSDavid du Colombier }
4177dd7cddfSDavid du Colombier 
4187dd7cddfSDavid du Colombier /* Set actual frequency and angle in a dictionary. */
4197dd7cddfSDavid du Colombier private int
dict_real_result(i_ctx_t * i_ctx_p,ref * pdict,const char * kstr,floatp val)4207dd7cddfSDavid du Colombier dict_real_result(i_ctx_t *i_ctx_p, ref * pdict, const char *kstr, floatp val)
4217dd7cddfSDavid du Colombier {
4227dd7cddfSDavid du Colombier     int code = 0;
4237dd7cddfSDavid du Colombier     ref *ignore;
4247dd7cddfSDavid du Colombier 
4257dd7cddfSDavid du Colombier     if (dict_find_string(pdict, kstr, &ignore) > 0) {
4267dd7cddfSDavid du Colombier 	ref rval;
4277dd7cddfSDavid du Colombier 
4287dd7cddfSDavid du Colombier 	check_dict_write(*pdict);
4297dd7cddfSDavid du Colombier 	make_real(&rval, val);
4307dd7cddfSDavid du Colombier 	code = idict_put_string(pdict, kstr, &rval);
4317dd7cddfSDavid du Colombier     }
4327dd7cddfSDavid du Colombier     return code;
4337dd7cddfSDavid du Colombier }
4347dd7cddfSDavid du Colombier private int
dict_spot_results(i_ctx_t * i_ctx_p,ref * pdict,const gs_spot_halftone * psp)4357dd7cddfSDavid du Colombier dict_spot_results(i_ctx_t *i_ctx_p, ref * pdict, const gs_spot_halftone * psp)
4367dd7cddfSDavid du Colombier {
4377dd7cddfSDavid du Colombier     int code;
4387dd7cddfSDavid du Colombier 
4397dd7cddfSDavid du Colombier     code = dict_real_result(i_ctx_p, pdict, "ActualFrequency",
4407dd7cddfSDavid du Colombier 			    psp->screen.actual_frequency);
4417dd7cddfSDavid du Colombier     if (code < 0)
4427dd7cddfSDavid du Colombier 	return code;
4437dd7cddfSDavid du Colombier     return dict_real_result(i_ctx_p, pdict, "ActualAngle",
4447dd7cddfSDavid du Colombier 			    psp->screen.actual_angle);
4457dd7cddfSDavid du Colombier }
4467dd7cddfSDavid du Colombier 
4477dd7cddfSDavid du Colombier /* Extract Width, Height, and TransferFunction from a dictionary. */
4487dd7cddfSDavid du Colombier private int
dict_threshold_common_params(const ref * pdict,gs_threshold_halftone_common * ptp,ref ** pptstring,ref * ptproc)4497dd7cddfSDavid du Colombier dict_threshold_common_params(const ref * pdict,
4507dd7cddfSDavid du Colombier 			     gs_threshold_halftone_common * ptp,
4517dd7cddfSDavid du Colombier 			     ref **pptstring, ref *ptproc)
4527dd7cddfSDavid du Colombier {
4537dd7cddfSDavid du Colombier     int code;
4547dd7cddfSDavid du Colombier 
4557dd7cddfSDavid du Colombier     check_dict_read(*pdict);
4567dd7cddfSDavid du Colombier     if ((code = dict_int_param(pdict, "Width", 1, 0x7fff, -1,
4577dd7cddfSDavid du Colombier 			       &ptp->width)) < 0 ||
4587dd7cddfSDavid du Colombier 	(code = dict_int_param(pdict, "Height", 1, 0x7fff, -1,
4597dd7cddfSDavid du Colombier 			       &ptp->height)) < 0 ||
4607dd7cddfSDavid du Colombier 	(code = dict_find_string(pdict, "Thresholds", pptstring)) <= 0 ||
4617dd7cddfSDavid du Colombier       (code = dict_proc_param(pdict, "TransferFunction", ptproc, false)) < 0
4627dd7cddfSDavid du Colombier 	)
4637dd7cddfSDavid du Colombier 	return (code < 0 ? code : e_undefined);
4647dd7cddfSDavid du Colombier     ptp->transfer_closure.proc = 0;
4657dd7cddfSDavid du Colombier     ptp->transfer_closure.data = 0;
4667dd7cddfSDavid du Colombier     return code;
4677dd7cddfSDavid du Colombier }
4687dd7cddfSDavid du Colombier 
4697dd7cddfSDavid du Colombier /* Extract threshold common parameters + Thresholds. */
4707dd7cddfSDavid du Colombier private int
dict_threshold_params(const ref * pdict,gs_threshold_halftone * ptp,ref * ptproc)4717dd7cddfSDavid du Colombier dict_threshold_params(const ref * pdict, gs_threshold_halftone * ptp,
4727dd7cddfSDavid du Colombier 		      ref * ptproc)
4737dd7cddfSDavid du Colombier {
4747dd7cddfSDavid du Colombier     ref *tstring;
4757dd7cddfSDavid du Colombier     int code =
4767dd7cddfSDavid du Colombier 	dict_threshold_common_params(pdict,
4777dd7cddfSDavid du Colombier 				     (gs_threshold_halftone_common *)ptp,
4787dd7cddfSDavid du Colombier 				     &tstring, ptproc);
4797dd7cddfSDavid du Colombier 
4807dd7cddfSDavid du Colombier     if (code < 0)
4817dd7cddfSDavid du Colombier 	return code;
4827dd7cddfSDavid du Colombier     check_read_type_only(*tstring, t_string);
4837dd7cddfSDavid du Colombier     if (r_size(tstring) != (long)ptp->width * ptp->height)
4847dd7cddfSDavid du Colombier 	return_error(e_rangecheck);
4857dd7cddfSDavid du Colombier     ptp->thresholds.data = tstring->value.const_bytes;
4867dd7cddfSDavid du Colombier     ptp->thresholds.size = r_size(tstring);
4877dd7cddfSDavid du Colombier     ptp->transfer = (code > 0 ? (gs_mapping_proc) 0 : gs_mapped_transfer);
4887dd7cddfSDavid du Colombier     return 0;
4897dd7cddfSDavid du Colombier }
4907dd7cddfSDavid du Colombier 
4917dd7cddfSDavid du Colombier /* Extract threshold common parameters + Thresholds, Width2, Height2, */
4927dd7cddfSDavid du Colombier /* BitsPerSample. */
4937dd7cddfSDavid du Colombier private int
dict_threshold2_params(const ref * pdict,gs_threshold2_halftone * ptp,ref * ptproc,gs_memory_t * mem)4947dd7cddfSDavid du Colombier dict_threshold2_params(const ref * pdict, gs_threshold2_halftone * ptp,
4957dd7cddfSDavid du Colombier 		       ref * ptproc, gs_memory_t *mem)
4967dd7cddfSDavid du Colombier {
4977dd7cddfSDavid du Colombier     ref *tstring;
4987dd7cddfSDavid du Colombier     int code =
4997dd7cddfSDavid du Colombier 	dict_threshold_common_params(pdict,
5007dd7cddfSDavid du Colombier 				     (gs_threshold_halftone_common *)ptp,
5017dd7cddfSDavid du Colombier 				     &tstring, ptproc);
5027dd7cddfSDavid du Colombier     int bps;
5037dd7cddfSDavid du Colombier     uint size;
5047dd7cddfSDavid du Colombier     int cw2, ch2;
5057dd7cddfSDavid du Colombier 
5067dd7cddfSDavid du Colombier     if (code < 0 ||
5077dd7cddfSDavid du Colombier 	(code = cw2 = dict_int_param(pdict, "Width2", 0, 0x7fff, 0,
5087dd7cddfSDavid du Colombier 				     &ptp->width2)) < 0 ||
5097dd7cddfSDavid du Colombier 	(code = ch2 = dict_int_param(pdict, "Height2", 0, 0x7fff, 0,
5107dd7cddfSDavid du Colombier 				     &ptp->height2)) < 0 ||
5117dd7cddfSDavid du Colombier 	(code = dict_int_param(pdict, "BitsPerSample", 8, 16, -1, &bps)) < 0
5127dd7cddfSDavid du Colombier 	)
5137dd7cddfSDavid du Colombier 	return code;
5147dd7cddfSDavid du Colombier     if ((bps != 8 && bps != 16) || cw2 != ch2 ||
5157dd7cddfSDavid du Colombier 	(!cw2 && (ptp->width2 == 0 || ptp->height2 == 0))
5167dd7cddfSDavid du Colombier 	)
5177dd7cddfSDavid du Colombier 	return_error(e_rangecheck);
5187dd7cddfSDavid du Colombier     ptp->bytes_per_sample = bps / 8;
5197dd7cddfSDavid du Colombier     switch (r_type(tstring)) {
5207dd7cddfSDavid du Colombier     case t_string:
5217dd7cddfSDavid du Colombier 	size = r_size(tstring);
5227dd7cddfSDavid du Colombier 	gs_bytestring_from_string(&ptp->thresholds, tstring->value.const_bytes,
5237dd7cddfSDavid du Colombier 				  size);
5247dd7cddfSDavid du Colombier 	break;
5257dd7cddfSDavid du Colombier     case t_astruct:
5267dd7cddfSDavid du Colombier 	if (gs_object_type(mem, tstring->value.pstruct) != &st_bytes)
5277dd7cddfSDavid du Colombier 	    return_error(e_typecheck);
5287dd7cddfSDavid du Colombier 	size = gs_object_size(mem, tstring->value.pstruct);
5297dd7cddfSDavid du Colombier 	gs_bytestring_from_bytes(&ptp->thresholds, r_ptr(tstring, byte),
5307dd7cddfSDavid du Colombier 				 0, size);
5317dd7cddfSDavid du Colombier 	break;
5327dd7cddfSDavid du Colombier     default:
5337dd7cddfSDavid du Colombier 	return_error(e_typecheck);
5347dd7cddfSDavid du Colombier     }
5357dd7cddfSDavid du Colombier     check_read(*tstring);
5367dd7cddfSDavid du Colombier     if (size != (ptp->width * ptp->height + ptp->width2 * ptp->height2) *
5377dd7cddfSDavid du Colombier 	ptp->bytes_per_sample)
5387dd7cddfSDavid du Colombier 	return_error(e_rangecheck);
5397dd7cddfSDavid du Colombier     return 0;
5407dd7cddfSDavid du Colombier }
541