xref: /plan9/sys/src/cmd/gs/src/ztrans.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
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(&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 	)
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, &params, &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(&params, 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, &params, &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(&params, TRANSPARENCY_MASK_Luminosity);
307     code = gs_begin_transparency_mask(igs, &params, &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