xref: /plan9/sys/src/cmd/gs/src/zht2.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1992, 1995, 1996, 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: zht2.c,v 1.14 2005/10/11 10:04:28 leonardo Exp $ */
18 /* Level 2 sethalftone operator */
19 #include "ghost.h"
20 #include "oper.h"
21 #include "gsstruct.h"
22 #include "gxdevice.h"		/* for gzht.h */
23 #include "gzht.h"
24 #include "estack.h"
25 #include "ialloc.h"
26 #include "iddict.h"
27 #include "idparam.h"
28 #include "igstate.h"
29 #include "icolor.h"
30 #include "iht.h"
31 #include "store.h"
32 #include "iname.h"
33 #include "zht2.h"
34 
35 /* Forward references */
36 private int dict_spot_params(const ref *, gs_spot_halftone *, ref *, ref *);
37 private int dict_spot_results(i_ctx_t *, ref *, const gs_spot_halftone *);
38 private int dict_threshold_params(const ref *, gs_threshold_halftone *,
39 				  ref *);
40 private int dict_threshold2_params(const ref *, gs_threshold2_halftone *,
41 				   ref *, gs_memory_t *);
42 
43 /*
44  * This routine translates a gs_separation_name value into a character string
45  * pointer and a string length.
46  */
47 int
gs_get_colorname_string(const gs_memory_t * mem,gs_separation_name colorname_index,unsigned char ** ppstr,unsigned int * pname_size)48 gs_get_colorname_string(const gs_memory_t *mem, gs_separation_name colorname_index,
49 			unsigned char **ppstr, unsigned int *pname_size)
50 {
51     ref nref;
52 
53     name_index_ref(mem, colorname_index, &nref);
54     name_string_ref(mem, &nref, &nref);
55     return obj_string_data(mem, &nref, (const unsigned char**) ppstr, pname_size);
56 }
57 
58 /* Dummy spot function */
59 private float
spot1_dummy(floatp x,floatp y)60 spot1_dummy(floatp x, floatp y)
61 {
62     return (x + y) / 2;
63 }
64 
65 /* <dict> <dict5> .sethalftone5 - */
66 private int sethalftone_finish(i_ctx_t *);
67 private int sethalftone_cleanup(i_ctx_t *);
68 private int
zsethalftone5(i_ctx_t * i_ctx_p)69 zsethalftone5(i_ctx_t *i_ctx_p)
70 {
71     os_ptr op = osp;
72     uint count;
73     gs_halftone_component *phtc;
74     gs_halftone_component *pc;
75     int code = 0;
76     int j;
77     gs_halftone *pht;
78     gx_device_halftone *pdht;
79     ref sprocs[GS_CLIENT_COLOR_MAX_COMPONENTS + 1];
80     ref tprocs[GS_CLIENT_COLOR_MAX_COMPONENTS + 1];
81     gs_memory_t *mem;
82     uint edepth = ref_stack_count(&e_stack);
83     int npop = 2;
84     int dict_enum = dict_first(op);
85     ref rvalue[2];
86     int cname, colorant_number;
87     byte * pname;
88     uint name_size;
89     int halftonetype, type = 0;
90     gs_state *pgs = igs;
91     int space_index = r_space_index(op - 1);
92 
93     mem = (gs_memory_t *) idmemory->spaces_indexed[space_index];
94 
95     check_type(*op, t_dictionary);
96     check_dict_read(*op);
97     check_type(op[-1], t_dictionary);
98     check_dict_read(op[-1]);
99 
100     /*
101      * We think that Type 2 and Type 4 halftones, like
102      * screens set by setcolorscreen, adapt automatically to
103      * the device color space, so we need to mark them
104      * with a different internal halftone type.
105      */
106     dict_int_param(op - 1, "HalftoneType", 1, 5, 0, &type);
107     halftonetype = (type == 2 || type == 4)
108     			? ht_type_multiple_colorscreen
109 			: ht_type_multiple;
110 
111     /* Count how many components that we will actually use. */
112 
113     for (count = 0; ;) {
114 	bool have_default = false;
115 
116 	/* Move to next element in the dictionary */
117 	if ((dict_enum = dict_next(op, dict_enum, rvalue)) == -1)
118 	    break;
119 	/*
120 	 * Verify that we have a valid component.  We may have a
121 	 * /HalfToneType entry.
122 	 */
123   	if (!r_has_type(&rvalue[1], t_dictionary))
124 	    continue;
125 
126 	/* Get the name of the component  verify that we will use it. */
127 	cname = name_index(mem, &rvalue[0]);
128 	code = gs_get_colorname_string(mem, cname, &pname, &name_size);
129 	if (code < 0)
130 	    break;
131 	colorant_number = gs_cname_to_colorant_number(pgs, pname, name_size,
132 						halftonetype);
133 	if (colorant_number < 0)
134 	    continue;
135 	else if (colorant_number == GX_DEVICE_COLOR_MAX_COMPONENTS) {
136 	    /* If here then we have the "Default" component */
137 	    if (have_default)
138 		return_error(e_rangecheck);
139 	    have_default = true;
140 	}
141 
142 	count++;
143 	/*
144 	 * Check to see if we have already reached the legal number of
145 	 * components.
146 	 */
147 	if (count > GS_CLIENT_COLOR_MAX_COMPONENTS + 1) {
148 	    code = gs_note_error(e_rangecheck);
149 	    break;
150         }
151     }
152 
153     check_estack(5);		/* for sampling Type 1 screens */
154     refset_null(sprocs, count);
155     refset_null(tprocs, count);
156     rc_alloc_struct_0(pht, gs_halftone, &st_halftone,
157 		      imemory, pht = 0, ".sethalftone5");
158     phtc = gs_alloc_struct_array(mem, count, gs_halftone_component,
159 				 &st_ht_component_element,
160 				 ".sethalftone5");
161     rc_alloc_struct_0(pdht, gx_device_halftone, &st_device_halftone,
162 		      imemory, pdht = 0, ".sethalftone5");
163     if (pht == 0 || phtc == 0 || pdht == 0) {
164 	j = 0; /* Quiet the compiler:
165 	          gs_note_error isn't necessarily identity,
166 		  so j could be left ununitialized. */
167 	code = gs_note_error(e_VMerror);
168     } else {
169         dict_enum = dict_first(op);
170 	for (j = 0, pc = phtc; ;) {
171 	    int type;
172 
173 	    /* Move to next element in the dictionary */
174 	    if ((dict_enum = dict_next(op, dict_enum, rvalue)) == -1)
175 	        break;
176 	    /*
177 	     * Verify that we have a valid component.  We may have a
178 	     * /HalfToneType entry.
179 	     */
180   	    if (!r_has_type(&rvalue[1], t_dictionary))
181 		continue;
182 
183 	    /* Get the name of the component */
184 	    cname = name_index(mem, &rvalue[0]);
185 	    code = gs_get_colorname_string(mem, cname, &pname, &name_size);
186 	    if (code < 0)
187 	        break;
188 	    colorant_number = gs_cname_to_colorant_number(pgs, pname, name_size,
189 						halftonetype);
190 	    if (colorant_number < 0)
191 		continue;		/* Do not use this component */
192 	    pc->cname = cname;
193 	    pc->comp_number = colorant_number;
194 
195 	    /* Now process the component dictionary */
196 	    check_dict_read(rvalue[1]);
197 	    if (dict_int_param(&rvalue[1], "HalftoneType", 1, 7, 0, &type) < 0) {
198 		code = gs_note_error(e_typecheck);
199 		break;
200 	    }
201 	    switch (type) {
202 		default:
203 		    code = gs_note_error(e_rangecheck);
204 		    break;
205 		case 1:
206 		    code = dict_spot_params(&rvalue[1], &pc->params.spot,
207 		    				sprocs + j, tprocs + j);
208 		    pc->params.spot.screen.spot_function = spot1_dummy;
209 		    pc->type = ht_type_spot;
210 		    break;
211 		case 3:
212 		    code = dict_threshold_params(&rvalue[1], &pc->params.threshold,
213 		    					tprocs + j);
214 		    pc->type = ht_type_threshold;
215 		    break;
216 		case 7:
217 		    code = dict_threshold2_params(&rvalue[1], &pc->params.threshold2,
218 		    					tprocs + j, imemory);
219 		    pc->type = ht_type_threshold2;
220 		    break;
221 	    }
222 	    if (code < 0)
223 		break;
224 	    pc++;
225 	    j++;
226 	}
227     }
228     if (code >= 0) {
229 	pht->type = halftonetype;
230 	pht->params.multiple.components = phtc;
231 	pht->params.multiple.num_comp = j;
232 	pht->params.multiple.get_colorname_string = gs_get_colorname_string;
233 	code = gs_sethalftone_prepare(igs, pht, pdht);
234     }
235     if (code >= 0) {
236 	/*
237 	 * Put the actual frequency and angle in the spot function component dictionaries.
238 	 */
239 	dict_enum = dict_first(op);
240 	for (pc = phtc; ; ) {
241 	    /* Move to next element in the dictionary */
242 	    if ((dict_enum = dict_next(op, dict_enum, rvalue)) == -1)
243 		break;
244 
245 	    /* Verify that we have a valid component */
246 	    if (!r_has_type(&rvalue[1], t_dictionary))
247 		continue;
248 
249 	    /* Get the name of the component and verify that we will use it. */
250 	    cname = name_index(mem, &rvalue[0]);
251 	    code = gs_get_colorname_string(mem, cname, &pname, &name_size);
252 	    if (code < 0)
253 	        break;
254 	    colorant_number = gs_cname_to_colorant_number(pgs, pname, name_size,
255 						halftonetype);
256 	    if (colorant_number < 0)
257 		continue;
258 
259 	    if (pc->type == ht_type_spot) {
260 		code = dict_spot_results(i_ctx_p, &rvalue[1], &pc->params.spot);
261 		if (code < 0)
262 		    break;
263 	    }
264 	    pc++;
265 	}
266     }
267     if (code >= 0) {
268 	/*
269 	 * Schedule the sampling of any Type 1 screens,
270 	 * and any (Type 1 or Type 3) TransferFunctions.
271 	 * Save the stack depths in case we have to back out.
272 	 */
273 	uint odepth = ref_stack_count(&o_stack);
274 	ref odict, odict5;
275 
276 	odict = op[-1];
277 	odict5 = *op;
278 	pop(2);
279 	op = osp;
280 	esp += 5;
281 	make_mark_estack(esp - 4, es_other, sethalftone_cleanup);
282 	esp[-3] = odict;
283 	make_istruct(esp - 2, 0, pht);
284 	make_istruct(esp - 1, 0, pdht);
285 	make_op_estack(esp, sethalftone_finish);
286 	for (j = 0; j < count; j++) {
287 	    gx_ht_order *porder = NULL;
288 
289 	    if (pdht->components == 0)
290 		porder = &pdht->order;
291 	    else {
292 		/* Find the component in pdht that matches component j in
293 		   the pht; gs_sethalftone_prepare() may permute these. */
294 		int k;
295 		int comp_number = phtc[j].comp_number;
296 		for (k = 0; k < count; k++) {
297 		    if (pdht->components[k].comp_number == comp_number) {
298 			porder = &pdht->components[k].corder;
299 			break;
300 		    }
301 		}
302 	    }
303 	    switch (phtc[j].type) {
304 	    case ht_type_spot:
305 		code = zscreen_enum_init(i_ctx_p, porder,
306 					 &phtc[j].params.spot.screen,
307 					 &sprocs[j], 0, 0, space_index);
308 		if (code < 0)
309 		    break;
310 		/* falls through */
311 	    case ht_type_threshold:
312 		if (!r_has_type(tprocs + j, t__invalid)) {
313 		    /* Schedule TransferFunction sampling. */
314 		    /****** check_xstack IS WRONG ******/
315 		    check_ostack(zcolor_remap_one_ostack);
316 		    check_estack(zcolor_remap_one_estack);
317 		    code = zcolor_remap_one(i_ctx_p, tprocs + j,
318 					    porder->transfer, igs,
319 					    zcolor_remap_one_finish);
320 		    op = osp;
321 		}
322 		break;
323 	    default:	/* not possible here, but to keep */
324 				/* the compilers happy.... */
325 		;
326 	    }
327 	    if (code < 0) {	/* Restore the stack. */
328 		ref_stack_pop_to(&o_stack, odepth);
329 		ref_stack_pop_to(&e_stack, edepth);
330 		op = osp;
331 		op[-1] = odict;
332 		*op = odict5;
333 		break;
334 	    }
335 	    npop = 0;
336 	}
337     }
338     if (code < 0) {
339 	gs_free_object(mem, pdht, ".sethalftone5");
340 	gs_free_object(mem, phtc, ".sethalftone5");
341 	gs_free_object(mem, pht, ".sethalftone5");
342 	return code;
343     }
344     pop(npop);
345     return (ref_stack_count(&e_stack) > edepth ? o_push_estack : 0);
346 }
347 
348 /* Install the halftone after sampling. */
349 private int
sethalftone_finish(i_ctx_t * i_ctx_p)350 sethalftone_finish(i_ctx_t *i_ctx_p)
351 {
352     gx_device_halftone *pdht = r_ptr(esp, gx_device_halftone);
353     int code;
354 
355     if (pdht->components)
356 	pdht->order = pdht->components[0].corder;
357     code = gx_ht_install(igs, r_ptr(esp - 1, gs_halftone), pdht);
358     if (code < 0)
359 	return code;
360     istate->halftone = esp[-2];
361     esp -= 4;
362     sethalftone_cleanup(i_ctx_p);
363     return o_pop_estack;
364 }
365 /* Clean up after installing the halftone. */
366 private int
sethalftone_cleanup(i_ctx_t * i_ctx_p)367 sethalftone_cleanup(i_ctx_t *i_ctx_p)
368 {
369     gx_device_halftone *pdht = r_ptr(&esp[4], gx_device_halftone);
370     gs_halftone *pht = r_ptr(&esp[3], gs_halftone);
371 
372     gs_free_object(pdht->rc.memory, pdht,
373 		   "sethalftone_cleanup(device halftone)");
374     gs_free_object(pht->rc.memory, pht,
375 		   "sethalftone_cleanup(halftone)");
376     return 0;
377 }
378 
379 /* ------ Initialization procedure ------ */
380 
381 const op_def zht2_l2_op_defs[] =
382 {
383     op_def_begin_level2(),
384     {"2.sethalftone5", zsethalftone5},
385 		/* Internal operators */
386     {"0%sethalftone_finish", sethalftone_finish},
387     op_def_end(0)
388 };
389 
390 /* ------ Internal routines ------ */
391 
392 /* Extract frequency, angle, spot function, and accurate screens flag */
393 /* from a dictionary. */
394 private int
dict_spot_params(const ref * pdict,gs_spot_halftone * psp,ref * psproc,ref * ptproc)395 dict_spot_params(const ref * pdict, gs_spot_halftone * psp,
396 		 ref * psproc, ref * ptproc)
397 {
398     int code;
399 
400     check_dict_read(*pdict);
401     if ((code = dict_float_param(pdict, "Frequency", 0.0,
402 				 &psp->screen.frequency)) != 0 ||
403 	(code = dict_float_param(pdict, "Angle", 0.0,
404 				 &psp->screen.angle)) != 0 ||
405       (code = dict_proc_param(pdict, "SpotFunction", psproc, false)) != 0 ||
406 	(code = dict_bool_param(pdict, "AccurateScreens",
407 				gs_currentaccuratescreens(),
408 				&psp->accurate_screens)) < 0 ||
409       (code = dict_proc_param(pdict, "TransferFunction", ptproc, false)) < 0
410 	)
411 	return (code < 0 ? code : e_undefined);
412     psp->transfer = (code > 0 ? (gs_mapping_proc) 0 : gs_mapped_transfer);
413     psp->transfer_closure.proc = 0;
414     psp->transfer_closure.data = 0;
415     return 0;
416 }
417 
418 /* Set actual frequency and angle in a dictionary. */
419 private int
dict_real_result(i_ctx_t * i_ctx_p,ref * pdict,const char * kstr,floatp val)420 dict_real_result(i_ctx_t *i_ctx_p, ref * pdict, const char *kstr, floatp val)
421 {
422     int code = 0;
423     ref *ignore;
424 
425     if (dict_find_string(pdict, kstr, &ignore) > 0) {
426 	ref rval;
427 
428 	check_dict_write(*pdict);
429 	make_real(&rval, val);
430 	code = idict_put_string(pdict, kstr, &rval);
431     }
432     return code;
433 }
434 private int
dict_spot_results(i_ctx_t * i_ctx_p,ref * pdict,const gs_spot_halftone * psp)435 dict_spot_results(i_ctx_t *i_ctx_p, ref * pdict, const gs_spot_halftone * psp)
436 {
437     int code;
438 
439     code = dict_real_result(i_ctx_p, pdict, "ActualFrequency",
440 			    psp->screen.actual_frequency);
441     if (code < 0)
442 	return code;
443     return dict_real_result(i_ctx_p, pdict, "ActualAngle",
444 			    psp->screen.actual_angle);
445 }
446 
447 /* Extract Width, Height, and TransferFunction from a dictionary. */
448 private int
dict_threshold_common_params(const ref * pdict,gs_threshold_halftone_common * ptp,ref ** pptstring,ref * ptproc)449 dict_threshold_common_params(const ref * pdict,
450 			     gs_threshold_halftone_common * ptp,
451 			     ref **pptstring, ref *ptproc)
452 {
453     int code;
454 
455     check_dict_read(*pdict);
456     if ((code = dict_int_param(pdict, "Width", 1, 0x7fff, -1,
457 			       &ptp->width)) < 0 ||
458 	(code = dict_int_param(pdict, "Height", 1, 0x7fff, -1,
459 			       &ptp->height)) < 0 ||
460 	(code = dict_find_string(pdict, "Thresholds", pptstring)) <= 0 ||
461       (code = dict_proc_param(pdict, "TransferFunction", ptproc, false)) < 0
462 	)
463 	return (code < 0 ? code : e_undefined);
464     ptp->transfer_closure.proc = 0;
465     ptp->transfer_closure.data = 0;
466     return code;
467 }
468 
469 /* Extract threshold common parameters + Thresholds. */
470 private int
dict_threshold_params(const ref * pdict,gs_threshold_halftone * ptp,ref * ptproc)471 dict_threshold_params(const ref * pdict, gs_threshold_halftone * ptp,
472 		      ref * ptproc)
473 {
474     ref *tstring;
475     int code =
476 	dict_threshold_common_params(pdict,
477 				     (gs_threshold_halftone_common *)ptp,
478 				     &tstring, ptproc);
479 
480     if (code < 0)
481 	return code;
482     check_read_type_only(*tstring, t_string);
483     if (r_size(tstring) != (long)ptp->width * ptp->height)
484 	return_error(e_rangecheck);
485     ptp->thresholds.data = tstring->value.const_bytes;
486     ptp->thresholds.size = r_size(tstring);
487     ptp->transfer = (code > 0 ? (gs_mapping_proc) 0 : gs_mapped_transfer);
488     return 0;
489 }
490 
491 /* Extract threshold common parameters + Thresholds, Width2, Height2, */
492 /* BitsPerSample. */
493 private int
dict_threshold2_params(const ref * pdict,gs_threshold2_halftone * ptp,ref * ptproc,gs_memory_t * mem)494 dict_threshold2_params(const ref * pdict, gs_threshold2_halftone * ptp,
495 		       ref * ptproc, gs_memory_t *mem)
496 {
497     ref *tstring;
498     int code =
499 	dict_threshold_common_params(pdict,
500 				     (gs_threshold_halftone_common *)ptp,
501 				     &tstring, ptproc);
502     int bps;
503     uint size;
504     int cw2, ch2;
505 
506     if (code < 0 ||
507 	(code = cw2 = dict_int_param(pdict, "Width2", 0, 0x7fff, 0,
508 				     &ptp->width2)) < 0 ||
509 	(code = ch2 = dict_int_param(pdict, "Height2", 0, 0x7fff, 0,
510 				     &ptp->height2)) < 0 ||
511 	(code = dict_int_param(pdict, "BitsPerSample", 8, 16, -1, &bps)) < 0
512 	)
513 	return code;
514     if ((bps != 8 && bps != 16) || cw2 != ch2 ||
515 	(!cw2 && (ptp->width2 == 0 || ptp->height2 == 0))
516 	)
517 	return_error(e_rangecheck);
518     ptp->bytes_per_sample = bps / 8;
519     switch (r_type(tstring)) {
520     case t_string:
521 	size = r_size(tstring);
522 	gs_bytestring_from_string(&ptp->thresholds, tstring->value.const_bytes,
523 				  size);
524 	break;
525     case t_astruct:
526 	if (gs_object_type(mem, tstring->value.pstruct) != &st_bytes)
527 	    return_error(e_typecheck);
528 	size = gs_object_size(mem, tstring->value.pstruct);
529 	gs_bytestring_from_bytes(&ptp->thresholds, r_ptr(tstring, byte),
530 				 0, size);
531 	break;
532     default:
533 	return_error(e_typecheck);
534     }
535     check_read(*tstring);
536     if (size != (ptp->width * ptp->height + ptp->width2 * ptp->height2) *
537 	ptp->bytes_per_sample)
538 	return_error(e_rangecheck);
539     return 0;
540 }
541