1 /* Copyright (C) 2000-2002 artofcode LLC. 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: ztrans.c,v 1.28 2005/10/04 06:30:02 ray Exp $ */
18 /* Transparency operators */
19 #include "string_.h"
20 #include "memory_.h"
21 #include "ghost.h"
22 #include "oper.h"
23 #include "gscspace.h" /* for gscolor2.h */
24 #include "gscolor2.h"
25 #include "gsipar3x.h"
26 #include "gstrans.h"
27 #include "gxiparam.h" /* for image enumerator */
28 #include "gxcspace.h"
29 #include "idict.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 "gsdfilt.h"
37 #include "gdevp14.h"
38
39 /* ------ Utilities ------ */
40
41 private int
set_float_value(i_ctx_t * i_ctx_p,int (* set_value)(gs_state *,floatp))42 set_float_value(i_ctx_t *i_ctx_p, int (*set_value)(gs_state *, floatp))
43 {
44 os_ptr op = osp;
45 double value;
46 int code;
47
48 if (real_param(op, &value) < 0)
49 return_op_typecheck(op);
50 if ((code = set_value(igs, value)) < 0)
51 return code;
52 pop(1);
53 return 0;
54 }
55
56 private int
current_float_value(i_ctx_t * i_ctx_p,float (* current_value)(const gs_state *))57 current_float_value(i_ctx_t *i_ctx_p,
58 float (*current_value)(const gs_state *))
59 {
60 os_ptr op = osp;
61
62 push(1);
63 make_real(op, current_value(igs));
64 return 0;
65 }
66
67 private int
enum_param(const gs_memory_t * mem,const ref * pnref,const char * const names[])68 enum_param(const gs_memory_t *mem, const ref *pnref,
69 const char *const names[])
70 {
71 const char *const *p;
72 ref nsref;
73
74 name_string_ref(mem, pnref, &nsref);
75 for (p = names; *p; ++p)
76 if (r_size(&nsref) == strlen(*p) &&
77 !memcmp(*p, nsref.value.const_bytes, r_size(&nsref))
78 )
79 return p - names;
80 return_error(e_rangecheck);
81 }
82
83 /* ------ Graphics state operators ------ */
84
85 private const char *const blend_mode_names[] = {
86 GS_BLEND_MODE_NAMES, 0
87 };
88
89 /* <modename> .setblendmode - */
90 private int
zsetblendmode(i_ctx_t * i_ctx_p)91 zsetblendmode(i_ctx_t *i_ctx_p)
92 {
93 os_ptr op = osp;
94 int code;
95
96 check_type(*op, t_name);
97 if ((code = enum_param(imemory, op, blend_mode_names)) < 0 ||
98 (code = gs_setblendmode(igs, code)) < 0
99 )
100 return code;
101 pop(1);
102 return 0;
103 }
104
105 /* - .currentblendmode <modename> */
106 private int
zcurrentblendmode(i_ctx_t * i_ctx_p)107 zcurrentblendmode(i_ctx_t *i_ctx_p)
108 {
109 os_ptr op = osp;
110 const char *mode_name = blend_mode_names[gs_currentblendmode(igs)];
111 ref nref;
112 int code = name_enter_string(imemory, mode_name, &nref);
113
114 if (code < 0)
115 return code;
116 push(1);
117 *op = nref;
118 return 0;
119 }
120
121 /* <0..1> .setopacityalpha - */
122 private int
zsetopacityalpha(i_ctx_t * i_ctx_p)123 zsetopacityalpha(i_ctx_t *i_ctx_p)
124 {
125 return set_float_value(i_ctx_p, gs_setopacityalpha);
126 }
127
128 /* - .currentopacityalpha <0..1> */
129 private int
zcurrentopacityalpha(i_ctx_t * i_ctx_p)130 zcurrentopacityalpha(i_ctx_t *i_ctx_p)
131 {
132 return current_float_value(i_ctx_p, gs_currentopacityalpha);
133 }
134
135 /* <0..1> .setshapealpha - */
136 private int
zsetshapealpha(i_ctx_t * i_ctx_p)137 zsetshapealpha(i_ctx_t *i_ctx_p)
138 {
139 return set_float_value(i_ctx_p, gs_setshapealpha);
140 }
141
142 /* - .currentshapealpha <0..1> */
143 private int
zcurrentshapealpha(i_ctx_t * i_ctx_p)144 zcurrentshapealpha(i_ctx_t *i_ctx_p)
145 {
146 return current_float_value(i_ctx_p, gs_currentshapealpha);
147 }
148
149 /* <bool> .settextknockout - */
150 private int
zsettextknockout(i_ctx_t * i_ctx_p)151 zsettextknockout(i_ctx_t *i_ctx_p)
152 {
153 os_ptr op = osp;
154
155 check_type(*op, t_boolean);
156 gs_settextknockout(igs, op->value.boolval);
157 pop(1);
158 return 0;
159 }
160
161 /* - .currenttextknockout <bool> */
162 private int
zcurrenttextknockout(i_ctx_t * i_ctx_p)163 zcurrenttextknockout(i_ctx_t *i_ctx_p)
164 {
165 os_ptr op = osp;
166
167 push(1);
168 make_bool(op, gs_currenttextknockout(igs));
169 return 0;
170 }
171
172 /* ------ Rendering stack operators ------ */
173
174 private int
rect_param(gs_rect * prect,os_ptr op)175 rect_param(gs_rect *prect, os_ptr op)
176 {
177 double coords[4];
178 int code = num_params(op, 4, coords);
179
180 if (code < 0)
181 return code;
182 prect->p.x = coords[0], prect->p.y = coords[1];
183 prect->q.x = coords[2], prect->q.y = coords[3];
184 return 0;
185 }
186
187 private int
mask_op(i_ctx_t * i_ctx_p,int (* mask_proc)(gs_state *,gs_transparency_channel_selector_t))188 mask_op(i_ctx_t *i_ctx_p,
189 int (*mask_proc)(gs_state *, gs_transparency_channel_selector_t))
190 {
191 int csel;
192 int code = int_param(osp, 1, &csel);
193
194 if (code < 0)
195 return code;
196 code = mask_proc(igs, csel);
197 if (code >= 0)
198 pop(1);
199 return code;
200
201 }
202
203 /* <paramdict> <llx> <lly> <urx> <ury> .begintransparencygroup - */
204 private int
zbegintransparencygroup(i_ctx_t * i_ctx_p)205 zbegintransparencygroup(i_ctx_t *i_ctx_p)
206 {
207 os_ptr op = osp;
208 os_ptr dop = op - 4;
209 gs_transparency_group_params_t params;
210 gs_rect bbox;
211 int code;
212
213 check_type(*dop, t_dictionary);
214 check_dict_read(*dop);
215 gs_trans_group_params_init(¶ms);
216 if ((code = dict_bool_param(dop, "Isolated", false, ¶ms.Isolated)) < 0 ||
217 (code = dict_bool_param(dop, "Knockout", false, ¶ms.Knockout)) < 0
218 )
219 return code;
220 code = rect_param(&bbox, op);
221 if (code < 0)
222 return code;
223 params.ColorSpace = gs_currentcolorspace(igs);
224 code = gs_begin_transparency_group(igs, ¶ms, &bbox);
225 if (code < 0)
226 return code;
227 pop(5);
228 return code;
229 }
230
231 /* - .discardtransparencygroup - */
232 private int
zdiscardtransparencygroup(i_ctx_t * i_ctx_p)233 zdiscardtransparencygroup(i_ctx_t *i_ctx_p)
234 {
235 if (gs_current_transparency_type(igs) != TRANSPARENCY_STATE_Group)
236 return_error(e_rangecheck);
237 return gs_discard_transparency_layer(igs);
238 }
239
240 /* - .endtransparencygroup - */
241 private int
zendtransparencygroup(i_ctx_t * i_ctx_p)242 zendtransparencygroup(i_ctx_t *i_ctx_p)
243 {
244 return gs_end_transparency_group(igs);
245 }
246
247 /* <paramdict> <llx> <lly> <urx> <ury> .begintransparencymaskgroup - */
248 private int tf_using_function(floatp, float *, void *);
249 private int
zbegintransparencymaskgroup(i_ctx_t * i_ctx_p)250 zbegintransparencymaskgroup(i_ctx_t *i_ctx_p)
251 {
252 os_ptr op = osp;
253 os_ptr dop = op - 4;
254 gs_transparency_mask_params_t params;
255 ref *pparam;
256 gs_rect bbox;
257 int code;
258 static const char *const subtype_names[] = {
259 GS_TRANSPARENCY_MASK_SUBTYPE_NAMES, 0
260 };
261
262 check_type(*dop, t_dictionary);
263 check_dict_read(*dop);
264 if (dict_find_string(dop, "Subtype", &pparam) <= 0)
265 return_error(e_rangecheck);
266 if ((code = enum_param(imemory, pparam, subtype_names)) < 0)
267 return code;
268 gs_trans_mask_params_init(¶ms, code);
269 if ((code = dict_floats_param(imemory, dop, "Background",
270 cs_num_components(gs_currentcolorspace(i_ctx_p->pgs)),
271 params.Background, NULL)) < 0
272 )
273 return code;
274 else if (code > 0)
275 params.Background_components = code;
276 if ((code = dict_floats_param(imemory, dop, "GrayBackground",
277 1, params.Background, NULL)) < 0
278 )
279 return code;
280 if (dict_find_string(dop, "TransferFunction", &pparam) >0) {
281 gs_function_t *pfn = ref_function(pparam);
282
283 if (pfn == 0 || pfn->params.m != 1 || pfn->params.n != 1)
284 return_error(e_rangecheck);
285 params.TransferFunction = tf_using_function;
286 params.TransferFunction_data = pfn;
287 }
288 code = rect_param(&bbox, op);
289 if (code < 0)
290 return code;
291 code = gs_begin_transparency_mask(igs, ¶ms, &bbox, false);
292 if (code < 0)
293 return code;
294 pop(5);
295 return code;
296 }
297
298 /* - .begintransparencymaskimage - */
299 private int
zbegintransparencymaskimage(i_ctx_t * i_ctx_p)300 zbegintransparencymaskimage(i_ctx_t *i_ctx_p)
301 {
302 gs_transparency_mask_params_t params;
303 gs_rect bbox = { { 0, 0} , { 1, 1} };
304 int code;
305
306 gs_trans_mask_params_init(¶ms, TRANSPARENCY_MASK_Luminosity);
307 code = gs_begin_transparency_mask(igs, ¶ms, &bbox, true);
308 if (code < 0)
309 return code;
310 return code;
311 }
312
313 /* Implement the TransferFunction using a Function. */
314 private int
tf_using_function(floatp in_val,float * out,void * proc_data)315 tf_using_function(floatp in_val, float *out, void *proc_data)
316 {
317 float in = in_val;
318 gs_function_t *const pfn = proc_data;
319
320 return gs_function_evaluate(pfn, &in, out);
321 }
322
323 /* - .discardtransparencymask - */
324 private int
zdiscardtransparencymask(i_ctx_t * i_ctx_p)325 zdiscardtransparencymask(i_ctx_t *i_ctx_p)
326 {
327 if (gs_current_transparency_type(igs) != TRANSPARENCY_STATE_Mask)
328 return_error(e_rangecheck);
329 return gs_discard_transparency_layer(igs);
330 }
331
332 /* <mask#> .endtransparencymask - */
333 private int
zendtransparencymask(i_ctx_t * i_ctx_p)334 zendtransparencymask(i_ctx_t *i_ctx_p)
335 {
336 return mask_op(i_ctx_p, gs_end_transparency_mask);
337 }
338
339 /* <mask#> .inittransparencymask - */
340 private int
zinittransparencymask(i_ctx_t * i_ctx_p)341 zinittransparencymask(i_ctx_t *i_ctx_p)
342 {
343 return mask_op(i_ctx_p, gs_init_transparency_mask);
344 }
345
346 /* ------ Soft-mask images ------ */
347
348 /* <dict> .image3x - */
349 private int mask_dict_param(const gs_memory_t *mem, os_ptr,
350 image_params *, const char *, int,
351 gs_image3x_mask_t *);
352 private int
zimage3x(i_ctx_t * i_ctx_p)353 zimage3x(i_ctx_t *i_ctx_p)
354 {
355 os_ptr op = osp;
356 gs_image3x_t image;
357 ref *pDataDict;
358 image_params ip_data;
359 int num_components =
360 gs_color_space_num_components(gs_currentcolorspace(igs));
361 int ignored;
362 int code;
363
364 check_type(*op, t_dictionary);
365 check_dict_read(*op);
366 gs_image3x_t_init(&image, NULL);
367 if (dict_find_string(op, "DataDict", &pDataDict) <= 0)
368 return_error(e_rangecheck);
369 if ((code = pixel_image_params(i_ctx_p, pDataDict,
370 (gs_pixel_image_t *)&image, &ip_data,
371 12, false)) < 0 ||
372 (code = dict_int_param(pDataDict, "ImageType", 1, 1, 0, &ignored)) < 0
373 )
374 return code;
375 /*
376 * We have to process the masks in the reverse order, because they
377 * insert their DataSource before the one(s) for the DataDict.
378 */
379 if ((code = mask_dict_param(imemory, op, &ip_data,
380 "ShapeMaskDict", num_components,
381 &image.Shape)) < 0 ||
382 (code = mask_dict_param(imemory, op, &ip_data,
383 "OpacityMaskDict", num_components,
384 &image.Opacity)) < 0
385 )
386 return code;
387 return zimage_setup(i_ctx_p, (gs_pixel_image_t *)&image,
388 &ip_data.DataSource[0],
389 image.CombineWithColor, 1);
390 }
391
392 /* Get one soft-mask dictionary parameter. */
393 private int
mask_dict_param(const gs_memory_t * mem,os_ptr op,image_params * pip_data,const char * dict_name,int num_components,gs_image3x_mask_t * pixm)394 mask_dict_param(const gs_memory_t *mem, os_ptr op,
395 image_params *pip_data, const char *dict_name,
396 int num_components, gs_image3x_mask_t *pixm)
397 {
398 ref *pMaskDict;
399 image_params ip_mask;
400 int ignored;
401 int code, mcode;
402
403 if (dict_find_string(op, dict_name, &pMaskDict) <= 0)
404 return 1;
405 if ((mcode = code = data_image_params(mem, pMaskDict, &pixm->MaskDict,
406 &ip_mask, false, 1, 12, false)) < 0 ||
407 (code = dict_int_param(pMaskDict, "ImageType", 1, 1, 0, &ignored)) < 0 ||
408 (code = dict_int_param(pMaskDict, "InterleaveType", 1, 3, -1,
409 &pixm->InterleaveType)) < 0 ||
410 (code = dict_floats_param(mem, op, "Matte", num_components,
411 pixm->Matte, NULL)) < 0
412 )
413 return code;
414 pixm->has_Matte = code > 0;
415 /*
416 * The MaskDict must have a DataSource iff InterleaveType == 3.
417 */
418 if ((pip_data->MultipleDataSources && pixm->InterleaveType != 3) ||
419 ip_mask.MultipleDataSources ||
420 mcode != (pixm->InterleaveType != 3)
421 )
422 return_error(e_rangecheck);
423 if (pixm->InterleaveType == 3) {
424 /* Insert the mask DataSource before the data DataSources. */
425 memmove(&pip_data->DataSource[1], &pip_data->DataSource[0],
426 (countof(pip_data->DataSource) - 1) *
427 sizeof(pip_data->DataSource[0]));
428 pip_data->DataSource[0] = ip_mask.DataSource[0];
429 }
430 return 0;
431 }
432
433 /* depth .pushpdf14devicefilter - */
434 /* this is a filter operator, but we include it here to maintain
435 modularity of the pdf14 transparency support */
436 private int
zpushpdf14devicefilter(i_ctx_t * i_ctx_p)437 zpushpdf14devicefilter(i_ctx_t *i_ctx_p)
438 {
439 int code;
440 os_ptr op = osp;
441
442 check_type(*op, t_integer);
443 code = gs_push_pdf14trans_device(igs);
444 if (code < 0)
445 return code;
446 pop(1);
447 return 0;
448 }
449
450 /* this is a filter operator, but we include it here to maintain
451 modularity of the pdf14 transparency support */
452 private int
zpoppdf14devicefilter(i_ctx_t * i_ctx_p)453 zpoppdf14devicefilter(i_ctx_t *i_ctx_p)
454 {
455 return gs_pop_pdf14trans_device(igs);
456 }
457
458 /* ------ Initialization procedure ------ */
459
460 /* We need to split the table because of the 16-element limit. */
461 const op_def ztrans1_op_defs[] = {
462 {"1.setblendmode", zsetblendmode},
463 {"0.currentblendmode", zcurrentblendmode},
464 {"1.setopacityalpha", zsetopacityalpha},
465 {"0.currentopacityalpha", zcurrentopacityalpha},
466 {"1.setshapealpha", zsetshapealpha},
467 {"0.currentshapealpha", zcurrentshapealpha},
468 {"1.settextknockout", zsettextknockout},
469 {"0.currenttextknockout", zcurrenttextknockout},
470 op_def_end(0)
471 };
472 const op_def ztrans2_op_defs[] = {
473 {"5.begintransparencygroup", zbegintransparencygroup},
474 {"0.discardtransparencygroup", zdiscardtransparencygroup},
475 {"0.endtransparencygroup", zendtransparencygroup},
476 {"5.begintransparencymaskgroup", zbegintransparencymaskgroup},
477 {"5.begintransparencymaskimage", zbegintransparencymaskimage},
478 {"0.discardtransparencymask", zdiscardtransparencymask},
479 {"1.endtransparencymask", zendtransparencymask},
480 {"1.inittransparencymask", zinittransparencymask},
481 {"1.image3x", zimage3x},
482 {"1.pushpdf14devicefilter", zpushpdf14devicefilter},
483 {"0.poppdf14devicefilter", zpoppdf14devicefilter},
484 op_def_end(0)
485 };
486