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