2 |
- |
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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 |
};
|