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