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