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