Commit | Line | Data |
---|---|---|
65a1152e WJ |
1 | /* Copyright (C) 1989, 1990, 1991 Aladdin Enterprises. All rights reserved. |
2 | Distributed by Free Software Foundation, Inc. | |
3 | ||
4 | This file is part of Ghostscript. | |
5 | ||
6 | Ghostscript is distributed in the hope that it will be useful, but | |
7 | WITHOUT ANY WARRANTY. No author or distributor accepts responsibility | |
8 | to anyone for the consequences of using it or for whether it serves any | |
9 | particular purpose or works at all, unless he says so in writing. Refer | |
10 | to the Ghostscript General Public License for full details. | |
11 | ||
12 | Everyone is granted permission to copy, modify and redistribute | |
13 | Ghostscript, but only under the conditions described in the Ghostscript | |
14 | General Public License. A copy of this license is supposed to have been | |
15 | given to you along with Ghostscript so you can know your rights and | |
16 | responsibilities. It should be in a file named COPYING. Among other | |
17 | things, the copyright notice and this notice must be preserved on all | |
18 | copies. */ | |
19 | ||
20 | /* zcolor.c */ | |
21 | /* Color operators for Ghostscript */ | |
22 | #include "ghost.h" | |
23 | #include "errors.h" | |
24 | #include "oper.h" | |
25 | #include "alloc.h" | |
26 | #include "estack.h" | |
27 | #include "iutil.h" | |
28 | #include "store.h" | |
29 | #include "gxfixed.h" | |
30 | #include "gxmatrix.h" | |
31 | #include "gzstate.h" | |
32 | #include "gxdevice.h" /* for gzcolor.h */ | |
33 | #include "gzcolor.h" | |
34 | #include "state.h" | |
35 | ||
36 | /* Import the 'for' operator */ | |
37 | extern int | |
38 | zfor(P1(os_ptr)), | |
39 | i_zfor; | |
40 | ||
41 | /* Define the number of estack slots needed for remap_one. */ | |
42 | #define remap_one_estack 3 | |
43 | ||
44 | /* Forward declarations */ | |
45 | private void tri_put(P2(os_ptr, float [3])); | |
46 | private int remap_one(P3(ref *, os_ptr, gx_transfer_map *)); | |
47 | private int | |
48 | remap_one_finish(P1(os_ptr)), | |
49 | i_remap_one_finish, | |
50 | remap_color(P1(os_ptr)), | |
51 | i_remap_color; | |
52 | ||
53 | /* Transfer functions for the library layer. */ | |
54 | /* These just return what's already in the map. */ | |
55 | #define tr_map(pgs,v,c)\ | |
56 | (pgs->transfer->c.values[(int)((v) * transfer_map_size + 0.5)] / max_color_param_float) | |
57 | private float | |
58 | transfer_red(gs_state *pgs, floatp value) | |
59 | { return tr_map(pgs, value, red); | |
60 | } | |
61 | private float | |
62 | transfer_green(gs_state *pgs, floatp value) | |
63 | { return tr_map(pgs, value, green); | |
64 | } | |
65 | private float | |
66 | transfer_blue(gs_state *pgs, floatp value) | |
67 | { return tr_map(pgs, value, blue); | |
68 | } | |
69 | private float | |
70 | transfer_gray(gs_state *pgs, floatp value) | |
71 | { return tr_map(pgs, value, gray); | |
72 | } | |
73 | #undef tr_map | |
74 | ||
75 | /* currentcolortransfer */ | |
76 | int | |
77 | zcurrentcolortransfer(register os_ptr op) | |
78 | { push(4); | |
79 | op[-3] = istate.transfer_procs.red; | |
80 | op[-2] = istate.transfer_procs.green; | |
81 | op[-1] = istate.transfer_procs.blue; | |
82 | *op = istate.transfer_procs.gray; | |
83 | return 0; | |
84 | } | |
85 | ||
86 | /* currentgray */ | |
87 | int | |
88 | zcurrentgray(register os_ptr op) | |
89 | { push(1); | |
90 | make_real(op, gs_currentgray(igs)); | |
91 | return 0; | |
92 | } | |
93 | ||
94 | /* currenthsbcolor */ | |
95 | int | |
96 | zcurrenthsbcolor(register os_ptr op) | |
97 | { float par[3]; | |
98 | gs_currenthsbcolor(igs, par); | |
99 | push(3); | |
100 | tri_put(op, par); | |
101 | return 0; | |
102 | } | |
103 | ||
104 | /* currentrgbcolor */ | |
105 | int | |
106 | zcurrentrgbcolor(register os_ptr op) | |
107 | { float par[3]; | |
108 | gs_currentrgbcolor(igs, par); | |
109 | push(3); | |
110 | tri_put(op, par); | |
111 | return 0; | |
112 | } | |
113 | ||
114 | /* currenttransfer */ | |
115 | int | |
116 | zcurrenttransfer(register os_ptr op) | |
117 | { push(1); | |
118 | *op = istate.transfer_procs.gray; | |
119 | return 0; | |
120 | } | |
121 | ||
122 | /* setcolortransfer */ | |
123 | int | |
124 | zsetcolortransfer(register os_ptr op) | |
125 | { int code; | |
126 | check_proc(op[-3]); | |
127 | check_proc(op[-2]); | |
128 | check_proc(op[-1]); | |
129 | check_proc(*op); | |
130 | istate.transfer_procs.red = op[-3]; | |
131 | istate.transfer_procs.green = op[-2]; | |
132 | istate.transfer_procs.blue = op[-1]; | |
133 | istate.transfer_procs.gray = *op; | |
134 | pop(4); op -= 4; | |
135 | check_estack(1 + remap_one_estack * 4); | |
136 | push_op_estack(remap_color, i_remap_color); | |
137 | (code = gs_setcolortransfer_remap(igs, transfer_red, transfer_green, transfer_blue, transfer_gray, 0)) < 0 || | |
138 | /* Use osp rather than op here, because remap_one pushes. */ | |
139 | (code = remap_one(&istate.transfer_procs.red, osp, &igs->transfer->red)) < 0 || | |
140 | (code = remap_one(&istate.transfer_procs.green, osp, &igs->transfer->green)) < 0 || | |
141 | (code = remap_one(&istate.transfer_procs.blue, osp, &igs->transfer->blue)) < 0 || | |
142 | (code = remap_one(&istate.transfer_procs.gray, osp, &igs->transfer->gray)) < 0; | |
143 | return code; | |
144 | } | |
145 | ||
146 | /* setgray */ | |
147 | int | |
148 | zsetgray(register os_ptr op) | |
149 | { float gray; | |
150 | int code; | |
151 | if ( (code = real_param(op, &gray)) < 0 || | |
152 | (code = gs_setgray(igs, gray)) < 0 | |
153 | ) | |
154 | return code; | |
155 | pop(1); | |
156 | return 0; | |
157 | } | |
158 | ||
159 | /* sethsbcolor */ | |
160 | int | |
161 | zsethsbcolor(register os_ptr op) | |
162 | { float par[3]; | |
163 | int code; | |
164 | if ( (code = num_params(op, 3, par)) < 0 || | |
165 | (code = gs_sethsbcolor(igs, par[0], par[1], par[2])) < 0 | |
166 | ) | |
167 | return code; | |
168 | pop(3); | |
169 | return 0; | |
170 | } | |
171 | ||
172 | /* setrgbcolor */ | |
173 | int | |
174 | zsetrgbcolor(register os_ptr op) | |
175 | { float par[3]; | |
176 | int code; | |
177 | if ( (code = num_params(op, 3, par)) < 0 || | |
178 | (code = gs_setrgbcolor(igs, par[0], par[1], par[2])) < 0 | |
179 | ) | |
180 | return code; | |
181 | pop(3); | |
182 | return 0; | |
183 | } | |
184 | ||
185 | /* settransfer */ | |
186 | int | |
187 | zsettransfer(register os_ptr op) | |
188 | { int code; | |
189 | check_proc(*op); | |
190 | istate.transfer_procs.red = istate.transfer_procs.green = | |
191 | istate.transfer_procs.blue = istate.transfer_procs.gray = *op; | |
192 | pop(1); op--; | |
193 | check_estack(1 + remap_one_estack); | |
194 | code = gs_settransfer_remap(igs, transfer_gray, 0); | |
195 | if ( code < 0 ) return code; | |
196 | push_op_estack(remap_color, i_remap_color); | |
197 | return remap_one(&istate.transfer_procs.gray, op, &igs->transfer->gray); | |
198 | } | |
199 | ||
200 | /* ------ Internal routines ------ */ | |
201 | ||
202 | /* Put 3 reals on the operand stack. */ | |
203 | private void | |
204 | tri_put(register os_ptr op, float pf3[3]) | |
205 | { make_real(op - 2, pf3[0]); | |
206 | make_real(op - 1, pf3[1]); | |
207 | make_real(op, pf3[2]); | |
208 | } | |
209 | ||
210 | /* Prepare to remap one color component. */ | |
211 | /* Use the 'for' operator to gather the values. */ | |
212 | /* The caller must have done the necessary check_estack. */ | |
213 | private int | |
214 | remap_one(ref *pproc, register os_ptr op, gx_transfer_map *pmap) | |
215 | { push(4); | |
216 | make_real(op - 3, 1.0); | |
217 | make_real(op - 2, -0.999999 / (transfer_map_size - 1)); | |
218 | make_real(op - 1, 0.0); | |
219 | *op = *pproc; | |
220 | ++esp; | |
221 | make_tasv(esp, t_string, 0, sizeof(*pmap), bytes, (byte *)pmap); | |
222 | push_op_estack(remap_one_finish, i_remap_one_finish); | |
223 | push_op_estack(zfor, i_zfor); | |
224 | return o_push_estack; | |
225 | } | |
226 | ||
227 | /* Store the result of remapping a component. */ | |
228 | private int | |
229 | remap_one_finish(os_ptr op) | |
230 | { int i; | |
231 | gx_transfer_map *pmap = (gx_transfer_map *)esp->value.bytes; | |
232 | for ( i = 0; i < transfer_map_size; i++ ) | |
233 | { float v; | |
234 | int code = real_param(op - i, &v); | |
235 | if ( code < 0 ) return 0; | |
236 | pmap->values[i] = gx_color_unit_param(v); | |
237 | } | |
238 | pop(transfer_map_size); | |
239 | esp--; /* pop pointer to transfer map */ | |
240 | return o_pop_estack; | |
241 | } | |
242 | ||
243 | /* Finally, remap the current color. */ | |
244 | private int | |
245 | remap_color(os_ptr op) | |
246 | { /* If we just did settransfer, as opposed to setcolortransfer, */ | |
247 | /* we need to copy the gray map to the r/g/b maps. */ | |
248 | gx_transfer *ptran = igs->transfer; | |
249 | if ( ptran->red.proc == ptran->gray.proc && | |
250 | ptran->green.proc == ptran->gray.proc && | |
251 | ptran->blue.proc == ptran->gray.proc | |
252 | ) | |
253 | { ptran->red = ptran->gray; | |
254 | ptran->green = ptran->gray; | |
255 | ptran->blue = ptran->gray; | |
256 | } | |
257 | return gx_remap_color(igs); | |
258 | } | |
259 | ||
260 | /* ------ Initialization procedure ------ */ | |
261 | ||
262 | op_def zcolor_op_defs[] = { | |
263 | {"0currentcolortransfer", zcurrentcolortransfer}, | |
264 | {"0currentgray", zcurrentgray}, | |
265 | {"0currenthsbcolor", zcurrenthsbcolor}, | |
266 | {"0currentrgbcolor", zcurrentrgbcolor}, | |
267 | {"0currenttransfer", zcurrenttransfer}, | |
268 | {"4setcolortransfer", zsetcolortransfer}, | |
269 | {"1setgray", zsetgray}, | |
270 | {"3sethsbcolor", zsethsbcolor}, | |
271 | {"3setrgbcolor", zsetrgbcolor}, | |
272 | {"1settransfer", zsettransfer}, | |
273 | /* Internal operators */ | |
274 | {"1%remap_one_finish", remap_one_finish, &i_remap_one_finish}, | |
275 | {"0%remap_color", remap_color, &i_remap_color}, | |
276 | op_def_end(0) | |
277 | }; |