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(&params);
216     if ((code = dict_bool_param(dop, "Isolated", false, &params.Isolated)) < 0 ||
217 	(code = dict_bool_param(dop, "Knockout", false, &params.Knockout)) < 0 ||
218 	(code = dict_bool_param(dop, ".image_with_SMask", false, &params.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, &params, &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(&params, 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, &params.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, &params, &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(&params, TRANSPARENCY_MASK_Luminosity);
325     code = gs_begin_transparency_mask(igs, &params, &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