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