/src/ghostpdl/psi/ztrans.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2021 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 | | /* Transparency operators */ |
18 | | #include "string_.h" |
19 | | #include "memory_.h" |
20 | | #include "ghost.h" |
21 | | #include "oper.h" |
22 | | #include "gscspace.h" /* for gscolor2.h */ |
23 | | #include "gscolor2.h" |
24 | | #include "gsipar3x.h" |
25 | | #include "gstrans.h" |
26 | | #include "gxiparam.h" /* for image enumerator */ |
27 | | #include "gxcspace.h" |
28 | | #include "idict.h" |
29 | | #include "idstack.h" |
30 | | #include "idparam.h" |
31 | | #include "ifunc.h" |
32 | | #include "igstate.h" |
33 | | #include "iimage.h" |
34 | | #include "iname.h" |
35 | | #include "store.h" |
36 | | #include "gspaint.h" /* gs_erasepage prototype */ |
37 | | #include "gdevdevn.h" |
38 | | #include "gxdevsop.h" |
39 | | #include "gxblend.h" |
40 | | #include "gdevp14.h" |
41 | | #include "gsicc_cms.h" |
42 | | |
43 | | /* ------ Utilities ------ */ |
44 | | |
45 | | |
46 | | static int |
47 | | current_float_value(i_ctx_t *i_ctx_p, |
48 | | float (*current_value)(const gs_gstate *)) |
49 | 10 | { |
50 | 10 | os_ptr op = osp; |
51 | | |
52 | 10 | push(1); |
53 | 10 | make_real(op, current_value(igs)); |
54 | 10 | return 0; |
55 | 10 | } |
56 | | |
57 | | static int |
58 | | enum_param(const gs_memory_t *mem, const ref *pnref, |
59 | | const char *const names[]) |
60 | 2 | { |
61 | 2 | const char *const *p; |
62 | 2 | ref nsref; |
63 | | |
64 | 2 | check_type(*pnref, t_name); |
65 | | |
66 | 2 | name_string_ref(mem, pnref, &nsref); |
67 | 38 | for (p = names; *p; ++p) |
68 | 36 | if (r_size(&nsref) == strlen(*p) && |
69 | 36 | !memcmp(*p, nsref.value.const_bytes, r_size(&nsref)) |
70 | 36 | ) |
71 | 0 | return p - names; |
72 | 2 | return_error(gs_error_rangecheck); |
73 | 2 | } |
74 | | |
75 | | /* ------ Graphics state operators ------ */ |
76 | | |
77 | | static const char *const blend_mode_names[] = { |
78 | | GS_BLEND_MODE_NAMES, 0 |
79 | | }; |
80 | | |
81 | | /* <modename> .setblendmode - */ |
82 | | static int |
83 | | zsetblendmode(i_ctx_t *i_ctx_p) |
84 | 4 | { |
85 | 4 | os_ptr op = osp; |
86 | 4 | int code; |
87 | | |
88 | 4 | check_type(*op, t_name); |
89 | 2 | if ((code = enum_param(imemory, op, blend_mode_names)) < 0 || |
90 | 2 | (code = gs_setblendmode(igs, code)) < 0 |
91 | 2 | ) |
92 | 2 | return code; |
93 | 0 | pop(1); |
94 | 0 | return 0; |
95 | 2 | } |
96 | | |
97 | | /* - .currentblendmode <modename> */ |
98 | | static int |
99 | | zcurrentblendmode(i_ctx_t *i_ctx_p) |
100 | 0 | { |
101 | 0 | os_ptr op = osp; |
102 | 0 | const char *mode_name = blend_mode_names[gs_currentblendmode(igs)]; |
103 | 0 | ref nref; |
104 | 0 | int code = name_enter_string(imemory, mode_name, &nref); |
105 | |
|
106 | 0 | if (code < 0) |
107 | 0 | return code; |
108 | 0 | push(1); |
109 | 0 | *op = nref; |
110 | 0 | return 0; |
111 | 0 | } |
112 | | |
113 | | /* <bool> .settextknockout - */ |
114 | | static int |
115 | | zsettextknockout(i_ctx_t *i_ctx_p) |
116 | 3 | { |
117 | 3 | os_ptr op = osp; |
118 | | |
119 | 3 | check_type(*op, t_boolean); |
120 | 0 | gs_settextknockout(igs, op->value.boolval); |
121 | 0 | pop(1); |
122 | 0 | return 0; |
123 | 3 | } |
124 | | |
125 | | /* - .currenttextknockout <bool> */ |
126 | | static int |
127 | | zcurrenttextknockout(i_ctx_t *i_ctx_p) |
128 | 0 | { |
129 | 0 | os_ptr op = osp; |
130 | |
|
131 | 0 | push(1); |
132 | 0 | make_bool(op, gs_currenttextknockout(igs)); |
133 | 0 | return 0; |
134 | 0 | } |
135 | | |
136 | | /* ------ Rendering stack operators ------ */ |
137 | | |
138 | | static int |
139 | | rect_param(gs_rect *prect, os_ptr op) |
140 | 8 | { |
141 | 8 | double coords[4]; |
142 | 8 | int code = num_params(op, 4, coords); |
143 | | |
144 | 8 | if (code < 0) |
145 | 0 | return code; |
146 | 8 | prect->p.x = coords[0], prect->p.y = coords[1]; |
147 | 8 | prect->q.x = coords[2], prect->q.y = coords[3]; |
148 | 8 | return 0; |
149 | 8 | } |
150 | | |
151 | | static int |
152 | | mask_op(i_ctx_t *i_ctx_p, |
153 | | int (*mask_proc)(gs_gstate *, gs_transparency_channel_selector_t)) |
154 | 0 | { |
155 | 0 | int csel; |
156 | 0 | int code = int_param(osp, 1, &csel); |
157 | |
|
158 | 0 | if (code < 0) |
159 | 0 | return code; |
160 | 0 | code = mask_proc(igs, csel); |
161 | 0 | if (code >= 0) |
162 | 0 | pop(1); |
163 | 0 | return code; |
164 | |
|
165 | 0 | } |
166 | | |
167 | | static int common_transparency_group(i_ctx_t *i_ctx_p, pdf14_compositor_operations group_type) |
168 | 15 | { |
169 | 15 | os_ptr op = osp; |
170 | 15 | os_ptr dop = op - 4; |
171 | 15 | gs_transparency_group_params_t params; |
172 | 15 | gs_rect bbox; |
173 | 15 | ref *dummy; |
174 | 15 | int code; |
175 | | |
176 | 15 | check_type(*dop, t_dictionary); |
177 | 8 | check_dict_read(*dop); |
178 | 8 | gs_trans_group_params_init(¶ms, 1.0); |
179 | 8 | if ((code = dict_bool_param(dop, "Isolated", false, ¶ms.Isolated)) < 0 || |
180 | 8 | (code = dict_bool_param(dop, "Knockout", false, ¶ms.Knockout)) < 0 || |
181 | 8 | (code = dict_bool_param(dop, ".image_with_SMask", false, ¶ms.image_with_SMask)) < 0 |
182 | 8 | ) |
183 | 0 | return code; |
184 | 8 | code = rect_param(&bbox, op); |
185 | 8 | if (code < 0) |
186 | 0 | return code; |
187 | | /* If the CS is not given in the transparency group dict, set to NULL */ |
188 | | /* so that the transparency code knows to inherit from the parent layer */ |
189 | 8 | if (dict_find_string(dop, "CS", &dummy) <= 0) { |
190 | 8 | params.ColorSpace = NULL; |
191 | 8 | } else { |
192 | | /* the PDF interpreter sets the colorspace, so use it */ |
193 | 0 | params.ColorSpace = gs_currentcolorspace(igs); |
194 | | /* Lets make sure that it is not an ICC color space that came from |
195 | | a PS CIE color space or a PS color space. These are 1-way color |
196 | | spaces and cannot be used for group color spaces */ |
197 | 0 | if (gs_color_space_is_PSCIE(params.ColorSpace)) |
198 | 0 | params.ColorSpace = NULL; |
199 | 0 | else if (gs_color_space_is_ICC(params.ColorSpace) && |
200 | 0 | params.ColorSpace->cmm_icc_profile_data != NULL && |
201 | 0 | params.ColorSpace->cmm_icc_profile_data->profile_handle != NULL) { |
202 | 0 | if (gscms_is_input(params.ColorSpace->cmm_icc_profile_data->profile_handle, |
203 | 0 | params.ColorSpace->cmm_icc_profile_data->memory)) |
204 | 0 | params.ColorSpace = NULL; |
205 | 0 | } |
206 | 0 | } |
207 | | |
208 | 8 | if (gs_getalphaisshape(igs)) { |
209 | 0 | params.group_shape = gs_getfillconstantalpha(igs); |
210 | 0 | params.group_opacity = 1.0; |
211 | 8 | } else { |
212 | 8 | params.group_opacity = gs_getfillconstantalpha(igs); |
213 | 8 | params.group_shape = 1.0; |
214 | 8 | } |
215 | | |
216 | 8 | code = gs_begin_transparency_group(igs, ¶ms, &bbox, group_type); |
217 | 8 | if (code < 0) |
218 | 4 | return code; |
219 | 4 | pop(5); |
220 | 4 | return code; |
221 | 8 | } |
222 | | |
223 | | /* <paramdict> <llx> <lly> <urx> <ury> .beginpagegroup - */ |
224 | | static int |
225 | | zbegintransparencypagegroup(i_ctx_t *i_ctx_p) |
226 | 0 | { |
227 | 0 | return common_transparency_group(i_ctx_p, PDF14_BEGIN_TRANS_PAGE_GROUP); |
228 | 0 | } |
229 | | |
230 | | /* <paramdict> <llx> <lly> <urx> <ury> .begintransparencygroup - */ |
231 | | static int |
232 | | zbegintransparencygroup(i_ctx_t *i_ctx_p) |
233 | 15 | { |
234 | 15 | return common_transparency_group(i_ctx_p, PDF14_BEGIN_TRANS_GROUP); |
235 | 15 | } |
236 | | |
237 | | /* - .endtransparencygroup - */ |
238 | | static int |
239 | | zendtransparencygroup(i_ctx_t *i_ctx_p) |
240 | 0 | { |
241 | 0 | return gs_end_transparency_group(igs); |
242 | 0 | } |
243 | | |
244 | | /* - .endtransparencytextgroup - */ |
245 | | static int |
246 | | zendtransparencytextgroup(i_ctx_t *i_ctx_p) |
247 | 0 | { |
248 | 0 | return gs_end_transparency_text_group(igs); |
249 | 0 | } |
250 | | |
251 | | /* - .begintransparencytextgroup - */ |
252 | | static int |
253 | | zbegintransparencytextgroup(i_ctx_t *i_ctx_p) |
254 | 0 | { |
255 | 0 | return gs_begin_transparency_text_group(igs); |
256 | 0 | } |
257 | | |
258 | | /* <cs_set?> <paramdict> <llx> <lly> <urx> <ury> .begintransparencymaskgroup - */ |
259 | | /* cs_set == false if we are inheriting the colorspace */ |
260 | | static int tf_using_function(double, float *, void *); |
261 | | static int |
262 | | zbegintransparencymaskgroup(i_ctx_t *i_ctx_p) |
263 | 0 | { |
264 | 0 | os_ptr op = osp; |
265 | 0 | os_ptr dop = op - 4; |
266 | 0 | gs_transparency_mask_params_t params; |
267 | 0 | ref *pparam; |
268 | 0 | gs_rect bbox; |
269 | 0 | int code; |
270 | 0 | static const char *const subtype_names[] = { |
271 | 0 | GS_TRANSPARENCY_MASK_SUBTYPE_NAMES, 0 |
272 | 0 | }; |
273 | |
|
274 | 0 | check_type(*dop, t_dictionary); |
275 | 0 | check_dict_read(*dop); |
276 | 0 | if (dict_find_string(dop, "Subtype", &pparam) <= 0) |
277 | 0 | return_error(gs_error_rangecheck); |
278 | 0 | if ((code = enum_param(imemory, pparam, subtype_names)) < 0) |
279 | 0 | return code; |
280 | 0 | gs_trans_mask_params_init(¶ms, code); |
281 | 0 | params.replacing = true; |
282 | 0 | if ((code = dict_floats_param(imemory, dop, "Background", |
283 | 0 | cs_num_components(gs_currentcolorspace(i_ctx_p->pgs)), |
284 | 0 | params.Background, NULL)) < 0) |
285 | 0 | return code; |
286 | 0 | else if (code > 0) |
287 | 0 | params.Background_components = code; |
288 | | |
289 | 0 | if ((code = dict_floats_param(imemory, dop, "GrayBackground", |
290 | 0 | 1, ¶ms.GrayBackground, NULL)) < 0) |
291 | 0 | return code; |
292 | 0 | if (dict_find_string(dop, "TransferFunction", &pparam) > 0) { |
293 | 0 | gs_function_t *pfn = ref_function(pparam); |
294 | |
|
295 | 0 | if (pfn == 0 || pfn->params.m != 1 || pfn->params.n != 1) |
296 | 0 | return_error(gs_error_rangecheck); |
297 | 0 | params.TransferFunction = tf_using_function; |
298 | 0 | params.TransferFunction_data = pfn; |
299 | 0 | } |
300 | 0 | code = rect_param(&bbox, op); |
301 | 0 | if (code < 0) |
302 | 0 | return code; |
303 | 0 | check_type(op[-5], t_boolean); |
304 | | |
305 | | /* Is the colorspace set for this mask ? */ |
306 | 0 | if (op[-5].value.boolval) { |
307 | 0 | params.ColorSpace = gs_currentcolorspace(igs); |
308 | | /* Lets make sure that it is not an ICC color space that came from |
309 | | a PS CIE color space or a PS color space. These are 1-way color |
310 | | spaces and cannot be used for group color spaces */ |
311 | 0 | if (gs_color_space_is_PSCIE(params.ColorSpace)) |
312 | 0 | params.ColorSpace = NULL; |
313 | 0 | else if (gs_color_space_is_ICC(params.ColorSpace) && |
314 | 0 | params.ColorSpace->cmm_icc_profile_data != NULL && |
315 | 0 | params.ColorSpace->cmm_icc_profile_data->profile_handle != NULL) { |
316 | 0 | if (gscms_is_input(params.ColorSpace->cmm_icc_profile_data->profile_handle, |
317 | 0 | params.ColorSpace->cmm_icc_profile_data->memory)) |
318 | 0 | params.ColorSpace = NULL; |
319 | 0 | } |
320 | 0 | } else { |
321 | 0 | params.ColorSpace = NULL; |
322 | 0 | } |
323 | 0 | code = gs_begin_transparency_mask(igs, ¶ms, &bbox, false); |
324 | 0 | if (code < 0) |
325 | 0 | return code; |
326 | 0 | pop(6); |
327 | 0 | return code; |
328 | 0 | } |
329 | | |
330 | | /* <paramdict> .begintransparencymaskimage <paramdict> */ |
331 | | static int |
332 | | zbegintransparencymaskimage(i_ctx_t *i_ctx_p) |
333 | 0 | { |
334 | 0 | os_ptr dop = osp; |
335 | 0 | gs_transparency_mask_params_t params; |
336 | 0 | gs_rect bbox = { { 0, 0} , { 1, 1} }; |
337 | 0 | int code; |
338 | 0 | gs_color_space *gray_cs = gs_cspace_new_DeviceGray(imemory); |
339 | |
|
340 | 0 | check_type(*dop, t_dictionary); |
341 | 0 | check_dict_read(*dop); |
342 | 0 | if (!gray_cs) |
343 | 0 | return_error(gs_error_VMerror); |
344 | 0 | gs_trans_mask_params_init(¶ms, TRANSPARENCY_MASK_Luminosity); |
345 | 0 | if ((code = dict_float_array_check_param(imemory, dop, "Matte", |
346 | 0 | GS_CLIENT_COLOR_MAX_COMPONENTS, |
347 | 0 | params.Matte, NULL, 0, |
348 | 0 | gs_error_rangecheck)) < 0) |
349 | 0 | return code; |
350 | 0 | else if (code > 0) |
351 | 0 | params.Matte_components = code; |
352 | 0 | code = gs_begin_transparency_mask(igs, ¶ms, &bbox, true); |
353 | 0 | if (code < 0) |
354 | 0 | return code; |
355 | 0 | rc_decrement_cs(gray_cs, "zbegintransparencymaskimage"); |
356 | 0 | return code; |
357 | 0 | } |
358 | | |
359 | | /* Implement the TransferFunction using a Function. */ |
360 | | static int |
361 | | tf_using_function(double in_val, float *out, void *proc_data) |
362 | 0 | { |
363 | 0 | float in = in_val; |
364 | 0 | gs_function_t *const pfn = proc_data; |
365 | |
|
366 | 0 | return gs_function_evaluate(pfn, &in, out); |
367 | 0 | } |
368 | | |
369 | | /* <mask#> .endtransparencymask - */ |
370 | | static int |
371 | | zendtransparencymask(i_ctx_t *i_ctx_p) |
372 | 0 | { |
373 | 0 | return mask_op(i_ctx_p, gs_end_transparency_mask); |
374 | 0 | } |
375 | | |
376 | | /* ------ Soft-mask images ------ */ |
377 | | |
378 | | /* <dict> .image3x - */ |
379 | | static int mask_dict_param(const gs_memory_t *mem, os_ptr, |
380 | | image_params *, const char *, int, |
381 | | gs_image3x_mask_t *); |
382 | | static int |
383 | | zimage3x(i_ctx_t *i_ctx_p) |
384 | 0 | { |
385 | 0 | os_ptr op = osp; |
386 | 0 | gs_image3x_t image; |
387 | 0 | ref *pDataDict; |
388 | 0 | image_params ip_data; |
389 | 0 | int num_components = |
390 | 0 | gs_color_space_num_components(gs_currentcolorspace(igs)); |
391 | 0 | int ignored; |
392 | 0 | int code; |
393 | |
|
394 | 0 | check_type(*op, t_dictionary); |
395 | 0 | check_dict_read(*op); |
396 | 0 | memset(&image, 0, sizeof(gs_image3x_t)); |
397 | 0 | gs_image3x_t_init(&image, NULL); |
398 | 0 | if (dict_find_string(op, "DataDict", &pDataDict) <= 0) |
399 | 0 | return_error(gs_error_rangecheck); |
400 | 0 | check_type(*pDataDict, t_dictionary); |
401 | 0 | if ((code = pixel_image_params(i_ctx_p, pDataDict, |
402 | 0 | (gs_pixel_image_t *)&image, &ip_data, |
403 | 0 | 16, gs_currentcolorspace(igs))) < 0 || |
404 | 0 | (code = dict_int_param(pDataDict, "ImageType", 1, 1, 0, &ignored)) < 0 |
405 | 0 | ) |
406 | 0 | return code; |
407 | | /* |
408 | | * We have to process the masks in the reverse order, because they |
409 | | * insert their DataSource before the one(s) for the DataDict. |
410 | | */ |
411 | 0 | if ((code = mask_dict_param(imemory, op, &ip_data, |
412 | 0 | "ShapeMaskDict", num_components, |
413 | 0 | &image.Shape)) < 0 || |
414 | 0 | (code = mask_dict_param(imemory, op, &ip_data, |
415 | 0 | "OpacityMaskDict", num_components, |
416 | 0 | &image.Opacity)) < 0 |
417 | 0 | ) |
418 | 0 | return code; |
419 | 0 | return zimage_setup(i_ctx_p, (gs_pixel_image_t *)&image, |
420 | 0 | &ip_data.DataSource[0], |
421 | 0 | image.CombineWithColor, 1); |
422 | 0 | } |
423 | | |
424 | | /* Get one soft-mask dictionary parameter. */ |
425 | | static int |
426 | | mask_dict_param(const gs_memory_t *mem, os_ptr op, |
427 | | image_params *pip_data, const char *dict_name, |
428 | | int num_components, gs_image3x_mask_t *pixm) |
429 | 0 | { |
430 | 0 | ref *pMaskDict; |
431 | 0 | image_params ip_mask; |
432 | 0 | int ignored; |
433 | 0 | int code, mcode; |
434 | |
|
435 | 0 | if (dict_find_string(op, dict_name, &pMaskDict) <= 0) |
436 | 0 | return 1; |
437 | 0 | if (!r_has_type(pMaskDict, t_dictionary)) |
438 | 0 | return gs_note_error(gs_error_typecheck); |
439 | | |
440 | 0 | if ((mcode = code = data_image_params(mem, pMaskDict, &pixm->MaskDict, |
441 | 0 | &ip_mask, false, 1, 16, false)) < 0 || |
442 | 0 | (code = dict_int_param(pMaskDict, "ImageType", 1, 1, 0, &ignored)) < 0 || |
443 | 0 | (code = dict_int_param(pMaskDict, "InterleaveType", 1, 3, -1, |
444 | 0 | &pixm->InterleaveType)) < 0 || |
445 | 0 | (code = dict_floats_param(mem, op, "Matte", num_components, |
446 | 0 | pixm->Matte, NULL)) < 0 |
447 | 0 | ) |
448 | 0 | return code; |
449 | 0 | pixm->has_Matte = code > 0; |
450 | | /* |
451 | | * The MaskDict must have a DataSource iff InterleaveType == 3. |
452 | | */ |
453 | 0 | if ((pip_data->MultipleDataSources && pixm->InterleaveType != 3) || |
454 | 0 | ip_mask.MultipleDataSources || |
455 | 0 | mcode != (pixm->InterleaveType != 3) |
456 | 0 | ) |
457 | 0 | return_error(gs_error_rangecheck); |
458 | 0 | if (pixm->InterleaveType == 3) { |
459 | | /* Insert the mask DataSource before the data DataSources. */ |
460 | 0 | memmove(&pip_data->DataSource[1], &pip_data->DataSource[0], |
461 | 0 | (countof(pip_data->DataSource) - 1) * |
462 | 0 | sizeof(pip_data->DataSource[0])); |
463 | 0 | pip_data->DataSource[0] = ip_mask.DataSource[0]; |
464 | 0 | } |
465 | 0 | return 0; |
466 | 0 | } |
467 | | |
468 | | /* depth .pushpdf14devicefilter - */ |
469 | | /* this is a filter operator, but we include it here to maintain |
470 | | modularity of the pdf14 transparency support */ |
471 | | static int |
472 | | zpushpdf14devicefilter(i_ctx_t *i_ctx_p) |
473 | 0 | { |
474 | 0 | int code; |
475 | 0 | int depth; |
476 | 0 | int spot_color_count = -1; /* default is 'unknown' spot color count */ |
477 | 0 | os_ptr op = osp; |
478 | 0 | gx_device *cdev = gs_currentdevice_inline(igs); |
479 | 0 | dict_stack_t *dstack = &(i_ctx_p->dict_stack); |
480 | 0 | ref_stack_t *rdstack = &dstack->stack; |
481 | 0 | const ref *puserdict = ref_stack_index(rdstack, ref_stack_count(rdstack) - 1 - |
482 | 0 | dstack->userdict_index); |
483 | |
|
484 | 0 | check_type(*op, t_integer); |
485 | 0 | depth = (int)op->value.intval; |
486 | |
|
487 | 0 | if (dev_proc(cdev, dev_spec_op)(cdev, gxdso_is_pdf14_device, NULL, 0) > 0) |
488 | 0 | return 0; /* ignore push_device if already is pdf14 device */ |
489 | | |
490 | | /* Bug 698087: In case some program uses our .pushpdf14devicefilter make */ |
491 | | /* sure that the device knows that we are using the pdf14 */ |
492 | | /* transparency. Note this will close and re-open the device */ |
493 | | /* and erase the page. This should not occur with PDF files. */ |
494 | | /* We don't do this if this is a push for the overprint_sim mode */ |
495 | 0 | if (depth >= 0 && cdev->page_uses_transparency == 0) { |
496 | 0 | gs_c_param_list list; |
497 | 0 | bool bool_true = 1; |
498 | |
|
499 | 0 | gs_c_param_list_write(&list, imemory); |
500 | 0 | code = param_write_bool((gs_param_list *)&list, "PageUsesTransparency", &bool_true); |
501 | 0 | if ( code >= 0) { |
502 | 0 | gs_c_param_list_read(&list); |
503 | 0 | code = gs_gstate_putdeviceparams(igs, cdev, (gs_param_list *)&list); |
504 | 0 | } |
505 | 0 | gs_c_param_list_release(&list); |
506 | 0 | if (code < 0) |
507 | 0 | return code; |
508 | 0 | if (cdev->is_open) { |
509 | 0 | if ((code = gs_closedevice((gx_device *)cdev)) < 0) |
510 | 0 | return code; |
511 | 0 | } |
512 | 0 | if ((code = gs_opendevice((gx_device *)cdev)) < 0) |
513 | 0 | return code; |
514 | 0 | if ((code = gs_erasepage(igs)) < 0) |
515 | 0 | return code; |
516 | 0 | } |
517 | | /* Get the PageSpotColors value from the userdict, if it is defined */ |
518 | 0 | code = dict_int_param(puserdict, "PageSpotColors", -1, max_int, -1, &spot_color_count); |
519 | 0 | if (code < 0) |
520 | 0 | return code; |
521 | | /* and finally actually push the compositor device */ |
522 | 0 | code = gs_push_pdf14trans_device(igs, false, true, depth, spot_color_count); |
523 | 0 | if (code < 0) |
524 | 0 | return code; |
525 | 0 | pop(1); |
526 | 0 | return 0; |
527 | 0 | } |
528 | | |
529 | | /* this is a filter operator, but we include it here to maintain |
530 | | modularity of the pdf14 transparency support */ |
531 | | static int |
532 | | zpoppdf14devicefilter(i_ctx_t *i_ctx_p) |
533 | 0 | { |
534 | 0 | return gs_pop_pdf14trans_device(igs, false); |
535 | 0 | } |
536 | | |
537 | | /* Something has gone terribly wrong */ |
538 | | static int |
539 | | zabortpdf14devicefilter(i_ctx_t *i_ctx_p) |
540 | 0 | { |
541 | 0 | return gs_abort_pdf14trans_device(igs); |
542 | 0 | } |
543 | | |
544 | | /* This is used to communicate to the transparency compositor |
545 | | when a q (save extended graphic state) occurs. Since |
546 | | the softmask is part of the graphic state we need to know |
547 | | this to handle clist processing properly */ |
548 | | |
549 | | static int |
550 | | zpushextendedgstate(i_ctx_t *i_ctx_p) |
551 | 0 | { |
552 | 0 | int code; |
553 | 0 | code = gs_push_transparency_state(igs); |
554 | 0 | return(code); |
555 | 0 | } |
556 | | |
557 | | /* This is used to communicate to the transparency compositor |
558 | | when a Q (restore extended graphic state) occurs. Since |
559 | | the softmask is part of the graphic state we need to know |
560 | | this to handle clist processing properly */ |
561 | | |
562 | | static int |
563 | | zpopextendedgstate(i_ctx_t *i_ctx_p) |
564 | 0 | { |
565 | 0 | int code; |
566 | 0 | code = gs_pop_transparency_state(igs, false); |
567 | 0 | return(code); |
568 | 0 | } |
569 | | |
570 | | static int |
571 | | zsetstrokeconstantalpha(i_ctx_t *i_ctx_p) |
572 | 0 | { |
573 | 0 | os_ptr op = osp; |
574 | 0 | double value; |
575 | |
|
576 | 0 | if (real_param(op, &value) < 0) |
577 | 0 | return_op_typecheck(op); |
578 | | |
579 | 0 | gs_setstrokeconstantalpha(igs, (float)value); |
580 | 0 | pop(1); |
581 | 0 | return 0; |
582 | 0 | } |
583 | | |
584 | | static int |
585 | | zgetstrokeconstantalpha(i_ctx_t *i_ctx_p) |
586 | 4 | { |
587 | 4 | return current_float_value(i_ctx_p, gs_getstrokeconstantalpha); |
588 | 4 | } |
589 | | |
590 | | static int |
591 | | zsetfillconstantalpha(i_ctx_t *i_ctx_p) |
592 | 0 | { |
593 | 0 | os_ptr op = osp; |
594 | 0 | double value; |
595 | |
|
596 | 0 | if (real_param(op, &value) < 0) |
597 | 0 | return_op_typecheck(op); |
598 | | |
599 | 0 | gs_setfillconstantalpha(igs, (float)value); |
600 | 0 | pop(1); |
601 | 0 | return 0; |
602 | 0 | } |
603 | | |
604 | | static int |
605 | | zgetfillconstantalpha(i_ctx_t *i_ctx_p) |
606 | 6 | { |
607 | 6 | return current_float_value(i_ctx_p, gs_getfillconstantalpha); |
608 | 6 | } |
609 | | |
610 | | static int |
611 | | zsetalphaisshape(i_ctx_t *i_ctx_p) |
612 | 0 | { |
613 | 0 | os_ptr op = osp; |
614 | |
|
615 | 0 | check_type(*op, t_boolean); |
616 | 0 | gs_setalphaisshape(igs, op->value.boolval); |
617 | 0 | pop(1); |
618 | |
|
619 | 0 | return 0; |
620 | 0 | } |
621 | | |
622 | | static int |
623 | | zgetalphaisshape(i_ctx_t *i_ctx_p) |
624 | 0 | { |
625 | 0 | os_ptr op = osp; |
626 | |
|
627 | 0 | push(1); |
628 | 0 | make_bool(op, gs_getalphaisshape(igs)); |
629 | 0 | return 0; |
630 | 0 | } |
631 | | |
632 | | static int |
633 | | zsetSMask(i_ctx_t *i_ctx_p) |
634 | 0 | { |
635 | 0 | os_ptr op = osp; |
636 | |
|
637 | 0 | check_op(1); |
638 | | |
639 | 0 | istate->SMask = *op; |
640 | 0 | pop(1); |
641 | 0 | return 0; |
642 | 0 | } |
643 | | |
644 | | static int |
645 | | zcurrentSMask(i_ctx_t *i_ctx_p) |
646 | 0 | { |
647 | 0 | os_ptr op = osp; |
648 | |
|
649 | 0 | push(1); |
650 | 0 | *op = istate->SMask; |
651 | 0 | return 0; |
652 | 0 | } |
653 | | |
654 | | /* ------ Initialization procedure ------ */ |
655 | | |
656 | | /* We need to split the table because of the 16-element limit. */ |
657 | | const op_def ztrans1_op_defs[] = { |
658 | | {"1.setblendmode", zsetblendmode}, |
659 | | {"0.currentblendmode", zcurrentblendmode}, |
660 | | {"1.settextknockout", zsettextknockout}, |
661 | | {"0.currenttextknockout", zcurrenttextknockout}, |
662 | | {"0.pushextendedgstate", zpushextendedgstate}, |
663 | | {"0.popextendedgstate", zpopextendedgstate}, |
664 | | op_def_end(0) |
665 | | }; |
666 | | const op_def ztrans2_op_defs[] = { |
667 | | {"5.begintransparencygroup", zbegintransparencygroup}, |
668 | | {"5.begintransparencypagegroup", zbegintransparencypagegroup}, |
669 | | {"0.endtransparencygroup", zendtransparencygroup}, |
670 | | { "0.endtransparencytextgroup", zendtransparencytextgroup }, |
671 | | { "0.begintransparencytextgroup", zbegintransparencytextgroup }, |
672 | | {"5.begintransparencymaskgroup", zbegintransparencymaskgroup}, |
673 | | {"1.begintransparencymaskimage", zbegintransparencymaskimage}, |
674 | | {"1.endtransparencymask", zendtransparencymask}, |
675 | | {"1.image3x", zimage3x}, |
676 | | {"1.pushpdf14devicefilter", zpushpdf14devicefilter}, |
677 | | {"0.poppdf14devicefilter", zpoppdf14devicefilter}, |
678 | | {"0.abortpdf14devicefilter", zabortpdf14devicefilter}, |
679 | | op_def_end(0) |
680 | | }; |
681 | | |
682 | | const op_def ztrans3_op_defs[] = { |
683 | | {"1.setstrokeconstantalpha", zsetstrokeconstantalpha}, |
684 | | {"0.currentstrokeconstantalpha", zgetstrokeconstantalpha}, |
685 | | {"1.setfillconstantalpha", zsetfillconstantalpha}, |
686 | | {"0.currentfillconstantalpha", zgetfillconstantalpha}, |
687 | | {"1.setalphaisshape", zsetalphaisshape}, |
688 | | {"0.currentalphaisshape", zgetalphaisshape}, |
689 | | {"1.setSMask", zsetSMask}, |
690 | | {"0.currentSMask", zcurrentSMask}, |
691 | | op_def_end(0) |
692 | | }; |