xref: /plan9/sys/src/cmd/gs/src/zht.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1989, 1991, 1993, 1994, 1997, 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: zht.c,v 1.8 2005/10/11 10:04:28 leonardo Exp $ */
18 /* Halftone definition operators */
19 #include "ghost.h"
20 #include "memory_.h"
21 #include "oper.h"
22 #include "estack.h"
23 #include "gsstruct.h"		/* must precede igstate.h, */
24 					/* because of #ifdef in gsht.h */
25 #include "ialloc.h"
26 #include "igstate.h"
27 #include "gsmatrix.h"
28 #include "gxdevice.h"		/* for gzht.h */
29 #include "gzht.h"
30 #include "gsstate.h"
31 #include "iht.h"		/* prototypes */
32 #include "store.h"
33 
34 /* Forward references */
35 private int screen_sample(i_ctx_t *);
36 private int set_screen_continue(i_ctx_t *);
37 private int screen_cleanup(i_ctx_t *);
38 
39 /* - .currenthalftone <dict> 0 */
40 /* - .currenthalftone <frequency> <angle> <proc> 1 */
41 /* - .currenthalftone <red_freq> ... <gray_proc> 2 */
42 private int
zcurrenthalftone(i_ctx_t * i_ctx_p)43 zcurrenthalftone(i_ctx_t *i_ctx_p)
44 {
45     os_ptr op = osp;
46     gs_halftone ht;
47 
48     gs_currenthalftone(igs, &ht);
49     switch (ht.type) {
50 	case ht_type_screen:
51 	    push(4);
52 	    make_real(op - 3, ht.params.screen.frequency);
53 	    make_real(op - 2, ht.params.screen.angle);
54 	    op[-1] = istate->screen_procs.gray;
55 	    make_int(op, 1);
56 	    break;
57 	case ht_type_colorscreen:
58 	    push(13);
59 	    {
60 		os_ptr opc = op - 12;
61 		gs_screen_halftone *pht =
62 		    &ht.params.colorscreen.screens.colored.red;
63 
64 		make_real(opc, pht->frequency);
65 		make_real(opc + 1, pht->angle);
66 		opc[2] = istate->screen_procs.red;
67 
68 		opc = op - 9;
69 		pht = &ht.params.colorscreen.screens.colored.green;
70 		make_real(opc, pht->frequency);
71 		make_real(opc + 1, pht->angle);
72 		opc[2] = istate->screen_procs.green;
73 
74 		opc = op - 6;
75 		pht = &ht.params.colorscreen.screens.colored.blue;
76 		make_real(opc, pht->frequency);
77 		make_real(opc + 1, pht->angle);
78 		opc[2] = istate->screen_procs.blue;
79 
80 		opc = op - 3;
81 		pht = &ht.params.colorscreen.screens.colored.gray;
82 		make_real(opc, pht->frequency);
83 		make_real(opc + 1, pht->angle);
84 		opc[2] = istate->screen_procs.gray;
85 	    }
86 	    make_int(op, 2);
87 	    break;
88 	default:		/* Screen was set by sethalftone. */
89 	    push(2);
90 	    op[-1] = istate->halftone;
91 	    make_int(op, 0);
92 	    break;
93     }
94     return 0;
95 }
96 
97 /* - .currentscreenlevels <int> */
98 private int
zcurrentscreenlevels(i_ctx_t * i_ctx_p)99 zcurrentscreenlevels(i_ctx_t *i_ctx_p)
100 {
101     os_ptr op = osp;
102 
103     push(1);
104     make_int(op, gs_currentscreenlevels(igs));
105     return 0;
106 }
107 
108 /* The setscreen operator is complex because it has to sample */
109 /* each pixel in the pattern cell, calling a procedure, and then */
110 /* sort the result into a whitening order. */
111 
112 /* Layout of stuff pushed on estack: */
113 /*      Control mark, */
114 /*      [other stuff for other screen-setting operators], */
115 /*      finishing procedure (or 0), */
116 /*      spot procedure, */
117 /*      enumeration structure (as bytes). */
118 #define snumpush 4
119 #define sproc esp[-1]
120 #define senum r_ptr(esp, gs_screen_enum)
121 
122 /* Forward references */
123 private int setscreen_finish(i_ctx_t *);
124 
125 /* <frequency> <angle> <proc> setscreen - */
126 private int
zsetscreen(i_ctx_t * i_ctx_p)127 zsetscreen(i_ctx_t *i_ctx_p)
128 {
129     os_ptr op = osp;
130     gs_screen_halftone screen;
131     gx_ht_order order;
132     int code = zscreen_params(op, &screen);
133     gs_memory_t *mem;
134     int space_index = r_space_index(op);
135 
136     if (code < 0)
137 	return code;
138     mem = (gs_memory_t *)idmemory->spaces_indexed[space_index];
139     /*
140      * Allocate the halftone in the same VM space as the procedure.
141      * This keeps the space relationships consistent.
142      */
143     code = gs_screen_order_init_memory(&order, igs, &screen,
144 				       gs_currentaccuratescreens(), mem);
145     if (code < 0)
146 	return code;
147     return zscreen_enum_init(i_ctx_p, &order, &screen, op, 3,
148 			     setscreen_finish, space_index);
149 }
150 /* We break out the body of this operator so it can be shared with */
151 /* the code for Type 1 halftones in sethalftone. */
152 int
zscreen_enum_init(i_ctx_t * i_ctx_p,const gx_ht_order * porder,gs_screen_halftone * psp,ref * pproc,int npop,int (* finish_proc)(i_ctx_t *),int space_index)153 zscreen_enum_init(i_ctx_t *i_ctx_p, const gx_ht_order * porder,
154 		  gs_screen_halftone * psp, ref * pproc, int npop,
155 		  int (*finish_proc)(i_ctx_t *), int space_index)
156 {
157     gs_screen_enum *penum;
158     gs_memory_t * mem = (gs_memory_t *)idmemory->spaces_indexed[space_index];
159     int code;
160 
161     check_estack(snumpush + 1);
162     penum = gs_screen_enum_alloc(mem, "setscreen");
163     if (penum == 0)
164 	return_error(e_VMerror);
165     make_struct(esp + snumpush, space_index << r_space_shift, penum);	/* do early for screen_cleanup in case of error */
166     code = gs_screen_enum_init_memory(penum, porder, igs, psp, mem);
167     if (code < 0) {
168 	screen_cleanup(i_ctx_p);
169 	return code;
170     }
171     /* Push everything on the estack */
172     make_mark_estack(esp + 1, es_other, screen_cleanup);
173     esp += snumpush;
174     make_op_estack(esp - 2, finish_proc);
175     sproc = *pproc;
176     push_op_estack(screen_sample);
177     pop(npop);
178     return o_push_estack;
179 }
180 /* Set up the next sample */
181 private int
screen_sample(i_ctx_t * i_ctx_p)182 screen_sample(i_ctx_t *i_ctx_p)
183 {
184     os_ptr op = osp;
185     gs_screen_enum *penum = senum;
186     gs_point pt;
187     int code = gs_screen_currentpoint(penum, &pt);
188     ref proc;
189 
190     switch (code) {
191 	default:
192 	    return code;
193 	case 1:
194 	    /* All done */
195 	    if (real_opproc(esp - 2) != 0)
196 		code = (*real_opproc(esp - 2)) (i_ctx_p);
197 	    esp -= snumpush;
198 	    screen_cleanup(i_ctx_p);
199 	    return (code < 0 ? code : o_pop_estack);
200 	case 0:
201 	    ;
202     }
203     push(2);
204     make_real(op - 1, pt.x);
205     make_real(op, pt.y);
206     proc = sproc;
207     push_op_estack(set_screen_continue);
208     *++esp = proc;
209     return o_push_estack;
210 }
211 /* Continuation procedure for processing sampled pixels. */
212 private int
set_screen_continue(i_ctx_t * i_ctx_p)213 set_screen_continue(i_ctx_t *i_ctx_p)
214 {
215     os_ptr op = osp;
216     double value;
217     int code = real_param(op, &value);
218 
219     if (code < 0)
220 	return code;
221     code = gs_screen_next(senum, value);
222     if (code < 0)
223 	return code;
224     pop(1);
225     return screen_sample(i_ctx_p);
226 }
227 /* Finish setscreen. */
228 private int
setscreen_finish(i_ctx_t * i_ctx_p)229 setscreen_finish(i_ctx_t *i_ctx_p)
230 {
231     gs_screen_install(senum);
232     istate->screen_procs.red = sproc;
233     istate->screen_procs.green = sproc;
234     istate->screen_procs.blue = sproc;
235     istate->screen_procs.gray = sproc;
236     make_null(&istate->halftone);
237     return 0;
238 }
239 /* Clean up after screen enumeration */
240 private int
screen_cleanup(i_ctx_t * i_ctx_p)241 screen_cleanup(i_ctx_t *i_ctx_p)
242 {
243     gs_screen_enum *penum = r_ptr(esp + snumpush, gs_screen_enum);
244 
245     gs_free_object(penum->halftone.rc.memory, penum, "screen_cleanup");
246     return 0;
247 }
248 
249 /* ------ Utility procedures ------ */
250 
251 /* Get parameters for a single screen. */
252 int
zscreen_params(os_ptr op,gs_screen_halftone * phs)253 zscreen_params(os_ptr op, gs_screen_halftone * phs)
254 {
255     double fa[2];
256     int code = num_params(op - 1, 2, fa);
257 
258     if (code < 0)
259 	return code;
260     check_proc(*op);
261     phs->frequency = fa[0];
262     phs->angle = fa[1];
263     return 0;
264 }
265 
266 /* ------ Initialization procedure ------ */
267 
268 const op_def zht_op_defs[] =
269 {
270     {"0.currenthalftone", zcurrenthalftone},
271     {"0.currentscreenlevels", zcurrentscreenlevels},
272     {"3setscreen", zsetscreen},
273 		/* Internal operators */
274     {"0%screen_sample", screen_sample},
275     {"1%set_screen_continue", set_screen_continue},
276     {"0%setscreen_finish", setscreen_finish},
277     op_def_end(0)
278 };
279