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