xref: /plan9/sys/src/cmd/gs/src/gstrans.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 2000 Aladdin Enterprises.  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: gstrans.c,v 1.25 2005/08/30 16:49:34 igor Exp $ */
18 /* Implementation of transparency, other than rendering */
19 #include "math_.h"
20 #include "memory_.h"
21 #include "gx.h"
22 #include "gserrors.h"
23 #include "gstrans.h"
24 #include "gsutil.h"
25 #include "gzstate.h"
26 #include "gxdevcli.h"
27 #include "gdevp14.h"
28 
29 #define PUSH_TS 0
30 
31 /* ------ Transparency-related graphics state elements ------ */
32 
33 int
gs_setblendmode(gs_state * pgs,gs_blend_mode_t mode)34 gs_setblendmode(gs_state *pgs, gs_blend_mode_t mode)
35 {
36 #ifdef DEBUG
37     if (gs_debug_c('v')) {
38 	static const char *const bm_names[] = { GS_BLEND_MODE_NAMES };
39 
40 	dlprintf1("[v](0x%lx)blend_mode = ", (ulong)pgs);
41 	if (mode >= 0 && mode < countof(bm_names))
42 	    dprintf1("%s\n", bm_names[mode]);
43 	else
44 	    dprintf1("%d??\n", (int)mode);
45     }
46 #endif
47     if (mode < 0 || mode > MAX_BLEND_MODE)
48 	return_error(gs_error_rangecheck);
49     pgs->blend_mode = mode;
50     return 0;
51 }
52 
53 gs_blend_mode_t
gs_currentblendmode(const gs_state * pgs)54 gs_currentblendmode(const gs_state *pgs)
55 {
56     return pgs->blend_mode;
57 }
58 
59 int
gs_setopacityalpha(gs_state * pgs,floatp alpha)60 gs_setopacityalpha(gs_state *pgs, floatp alpha)
61 {
62     if_debug2('v', "[v](0x%lx)opacity.alpha = %g\n", (ulong)pgs, alpha);
63     pgs->opacity.alpha = (alpha < 0.0 ? 0.0 : alpha > 1.0 ? 1.0 : alpha);
64     return 0;
65 }
66 
67 float
gs_currentopacityalpha(const gs_state * pgs)68 gs_currentopacityalpha(const gs_state *pgs)
69 {
70     return pgs->opacity.alpha;
71 }
72 
73 int
gs_setshapealpha(gs_state * pgs,floatp alpha)74 gs_setshapealpha(gs_state *pgs, floatp alpha)
75 {
76     if_debug2('v', "[v](0x%lx)shape.alpha = %g\n", (ulong)pgs, alpha);
77     pgs->shape.alpha = (alpha < 0.0 ? 0.0 : alpha > 1.0 ? 1.0 : alpha);
78     return 0;
79 }
80 
81 float
gs_currentshapealpha(const gs_state * pgs)82 gs_currentshapealpha(const gs_state *pgs)
83 {
84     return pgs->shape.alpha;
85 }
86 
87 int
gs_settextknockout(gs_state * pgs,bool knockout)88 gs_settextknockout(gs_state *pgs, bool knockout)
89 {
90     if_debug2('v', "[v](0x%lx)text_knockout = %s\n", (ulong)pgs,
91 	      (knockout ? "true" : "false"));
92     pgs->text_knockout = knockout;
93     return 0;
94 }
95 
96 bool
gs_currenttextknockout(const gs_state * pgs)97 gs_currenttextknockout(const gs_state *pgs)
98 {
99     return pgs->text_knockout;
100 }
101 
102 /* ------ Transparency rendering stack ------ */
103 
104 gs_transparency_state_type_t
gs_current_transparency_type(const gs_state * pgs)105 gs_current_transparency_type(const gs_state *pgs)
106 {
107     return (pgs->transparency_stack == 0 ? 0 :
108 	    pgs->transparency_stack->type);
109 }
110 
111 /* Support for dummy implementation */
112 gs_private_st_ptrs1(st_transparency_state, gs_transparency_state_t,
113 		    "gs_transparency_state_t", transparency_state_enum_ptrs,
114 		    transparency_state_reloc_ptrs, saved);
115 #if PUSH_TS
116 private int
push_transparency_stack(gs_state * pgs,gs_transparency_state_type_t type,client_name_t cname)117 push_transparency_stack(gs_state *pgs, gs_transparency_state_type_t type,
118 			client_name_t cname)
119 {
120     gs_transparency_state_t *pts =
121 	gs_alloc_struct(pgs->memory, gs_transparency_state_t,
122 			&st_transparency_state, cname);
123 
124     if (pts == 0)
125 	return_error(gs_error_VMerror);
126     pts->saved = pgs->transparency_stack;
127     pts->type = type;
128     pgs->transparency_stack = pts;
129     return 0;
130 }
131 #endif
132 private void
pop_transparency_stack(gs_state * pgs,client_name_t cname)133 pop_transparency_stack(gs_state *pgs, client_name_t cname)
134 {
135     gs_transparency_state_t *pts = pgs->transparency_stack; /* known non-0 */
136     gs_transparency_state_t *saved = pts->saved;
137 
138     gs_free_object(pgs->memory, pts, cname);
139     pgs->transparency_stack = saved;
140 
141 }
142 
143 /*
144  * Push a PDF 1.4 transparency compositor onto the current device. Note that
145  * if the current device already is a PDF 1.4 transparency compositor, the
146  * create_compositor will update its parameters but not create a new
147  * compositor device.
148  */
149 private int
gs_state_update_pdf14trans(gs_state * pgs,gs_pdf14trans_params_t * pparams)150 gs_state_update_pdf14trans(gs_state * pgs, gs_pdf14trans_params_t * pparams)
151 {
152     gs_imager_state * pis = (gs_imager_state *)pgs;
153     gx_device * dev = pgs->device;
154     gx_device * pdf14dev;
155     int code;
156 
157     /*
158      * Send the PDF 1.4 create compositor action specified by the parameters.
159      */
160     code = send_pdf14trans(pis, dev, &pdf14dev, pparams, pgs->memory);
161     /*
162      * If we created a new PDF 1.4 compositor device then we need to install it
163      * into the graphics state.
164      */
165     if (code >= 0 && pdf14dev != dev)
166         gx_set_device_only(pgs, pdf14dev);
167 
168     return code;
169 }
170 
171 void
gs_trans_group_params_init(gs_transparency_group_params_t * ptgp)172 gs_trans_group_params_init(gs_transparency_group_params_t *ptgp)
173 {
174     ptgp->ColorSpace = 0;	/* bogus, but can't do better */
175     ptgp->Isolated = false;
176     ptgp->Knockout = false;
177 }
178 
179 int
gs_begin_transparency_group(gs_state * pgs,const gs_transparency_group_params_t * ptgp,const gs_rect * pbbox)180 gs_begin_transparency_group(gs_state *pgs,
181 			    const gs_transparency_group_params_t *ptgp,
182 			    const gs_rect *pbbox)
183 {
184     gs_pdf14trans_params_t params = { 0 };
185 
186 #ifdef DEBUG
187     if (gs_debug_c('v')) {
188 	static const char *const cs_names[] = {
189 	    GS_COLOR_SPACE_TYPE_NAMES
190 	};
191 
192 	dlprintf5("[v](0x%lx)begin_transparency_group [%g %g %g %g]\n",
193 		  (ulong)pgs, pbbox->p.x, pbbox->p.y, pbbox->q.x, pbbox->q.y);
194 	if (ptgp->ColorSpace)
195 	    dprintf1("     CS = %s",
196 		cs_names[(int)gs_color_space_get_index(ptgp->ColorSpace)]);
197 	else
198 	    dputs("     (no CS)");
199 	dprintf2("  Isolated = %d  Knockout = %d\n",
200 		 ptgp->Isolated, ptgp->Knockout);
201     }
202 #endif
203     /*
204      * Put parameters into a compositor parameter and then call the
205      * create_compositor.  This will pass the data to the PDF 1.4
206      * transparency device.
207      */
208     params.pdf14_op = PDF14_BEGIN_TRANS_GROUP;
209     params.Isolated = ptgp->Isolated;
210     params.Knockout = ptgp->Knockout;
211     params.opacity = pgs->opacity;
212     params.shape = pgs->shape;
213     params.blend_mode = pgs->blend_mode;
214     /*
215      * We are currently doing nothing with the colorspace.  Currently
216      * the blending colorspace is based upon the processs color model
217      * of the output device.
218      */
219     params.bbox = *pbbox;
220     return gs_state_update_pdf14trans(pgs, &params);
221 }
222 
223 int
gx_begin_transparency_group(gs_imager_state * pis,gx_device * pdev,const gs_pdf14trans_params_t * pparams)224 gx_begin_transparency_group(gs_imager_state * pis, gx_device * pdev,
225 				const gs_pdf14trans_params_t * pparams)
226 {
227     gs_transparency_group_params_t tgp = {0};
228     gs_rect bbox;
229 
230     if (pparams->Background_components != 0 &&
231 	pparams->Background_components != pdev->color_info.num_components)
232 	return_error(gs_error_rangecheck);
233     tgp.Isolated = pparams->Isolated;
234     tgp.Knockout = pparams->Knockout;
235     pis->opacity.alpha = pparams->opacity.alpha;
236     pis->shape.alpha = pparams->shape.alpha;
237     pis->blend_mode = pparams->blend_mode;
238     bbox = pparams->bbox;
239 #ifdef DEBUG
240     if (gs_debug_c('v')) {
241 	static const char *const cs_names[] = {
242 	    GS_COLOR_SPACE_TYPE_NAMES
243 	};
244 
245 	dlprintf5("[v](0x%lx)begin_transparency_group [%g %g %g %g]\n",
246 		  (ulong)pis, bbox.p.x, bbox.p.y, bbox.q.x, bbox.q.y);
247 	if (tgp.ColorSpace)
248 	    dprintf1("     CS = %s",
249 		cs_names[(int)gs_color_space_get_index(tgp.ColorSpace)]);
250 	else
251 	    dputs("     (no CS)");
252 	dprintf2("  Isolated = %d  Knockout = %d\n",
253 		 tgp.Isolated, tgp.Knockout);
254     }
255 #endif
256     if (dev_proc(pdev, begin_transparency_group) != 0)
257 	return (*dev_proc(pdev, begin_transparency_group)) (pdev, &tgp,
258 							&bbox, pis, NULL, NULL);
259     else
260 	return 0;
261 }
262 
263 int
gs_end_transparency_group(gs_state * pgs)264 gs_end_transparency_group(gs_state *pgs)
265 {
266     gs_pdf14trans_params_t params = { 0 };
267 
268     params.pdf14_op = PDF14_END_TRANS_GROUP;  /* Other parameters not used */
269     return gs_state_update_pdf14trans(pgs, &params);
270 }
271 
272 int
gx_end_transparency_group(gs_imager_state * pis,gx_device * pdev)273 gx_end_transparency_group(gs_imager_state * pis, gx_device * pdev)
274 {
275     if (dev_proc(pdev, end_transparency_group) != 0)
276 	return (*dev_proc(pdev, end_transparency_group)) (pdev, pis, NULL);
277     else
278 	return 0;
279 }
280 
281 /*
282  * Handler for identity mask transfer functions.
283  */
284 private int
mask_transfer_identity(floatp in,float * out,void * proc_data)285 mask_transfer_identity(floatp in, float *out, void *proc_data)
286 {
287     *out = (float) in;
288     return 0;
289 }
290 
291 void
gs_trans_mask_params_init(gs_transparency_mask_params_t * ptmp,gs_transparency_mask_subtype_t subtype)292 gs_trans_mask_params_init(gs_transparency_mask_params_t *ptmp,
293 			  gs_transparency_mask_subtype_t subtype)
294 {
295     ptmp->subtype = subtype;
296     ptmp->Background_components = 0;
297     ptmp->TransferFunction = mask_transfer_identity;
298     ptmp->TransferFunction_data = 0;
299 }
300 
301 int
gs_begin_transparency_mask(gs_state * pgs,const gs_transparency_mask_params_t * ptmp,const gs_rect * pbbox,bool mask_is_image)302 gs_begin_transparency_mask(gs_state * pgs,
303 			   const gs_transparency_mask_params_t * ptmp,
304 			   const gs_rect * pbbox, bool mask_is_image)
305 {
306     gs_pdf14trans_params_t params = { 0 };
307     const int l = sizeof(params.Background[0]) * ptmp->Background_components;
308     int i;
309 
310     if_debug8('v', "[v](0x%lx)begin_transparency_mask [%g %g %g %g]\n\
311       subtype = %d  Background_components = %d  %s\n",
312 	      (ulong)pgs, pbbox->p.x, pbbox->p.y, pbbox->q.x, pbbox->q.y,
313 	      (int)ptmp->subtype, ptmp->Background_components,
314 	      (ptmp->TransferFunction == mask_transfer_identity ? "no TR" :
315 	       "has TR"));
316     params.pdf14_op = PDF14_BEGIN_TRANS_MASK;
317     params.bbox = *pbbox;
318     params.subtype = ptmp->subtype;
319     params.Background_components = ptmp->Background_components;
320     memcpy(params.Background, ptmp->Background, l);
321     params.GrayBackground = ptmp->GrayBackground;
322     params.transfer_function = ptmp->TransferFunction_data;
323     params.function_is_identity =
324 	    (ptmp->TransferFunction == mask_transfer_identity);
325     params.mask_is_image = mask_is_image;
326     /* Sample the transfer function */
327     for (i = 0; i < MASK_TRANSFER_FUNCTION_SIZE; i++) {
328 	float in = (float)(i * (1.0 / (MASK_TRANSFER_FUNCTION_SIZE - 1)));
329 	float out;
330 
331 	ptmp->TransferFunction(in, &out, ptmp->TransferFunction_data);
332 	params.transfer_fn[i] = (byte)floor((double)(out * 255 + 0.5));
333     }
334     return gs_state_update_pdf14trans(pgs, &params);
335 }
336 
337 int
gx_begin_transparency_mask(gs_imager_state * pis,gx_device * pdev,const gs_pdf14trans_params_t * pparams)338 gx_begin_transparency_mask(gs_imager_state * pis, gx_device * pdev,
339 				const gs_pdf14trans_params_t * pparams)
340 {
341     gx_transparency_mask_params_t tmp;
342     const int l = sizeof(pparams->Background[0]) * pparams->Background_components;
343 
344     tmp.subtype = pparams->subtype;
345     tmp.Background_components = pparams->Background_components;
346     memcpy(tmp.Background, pparams->Background, l);
347     tmp.GrayBackground = pparams->GrayBackground;
348     tmp.function_is_identity = pparams->function_is_identity;
349     memcpy(tmp.transfer_fn, pparams->transfer_fn, size_of(tmp.transfer_fn));
350     if_debug8('v', "[v](0x%lx)begin_transparency_mask [%g %g %g %g]\n\
351       subtype = %d  Background_components = %d  %s\n",
352 	      (ulong)pis, pparams->bbox.p.x, pparams->bbox.p.y,
353 	      pparams->bbox.q.x, pparams->bbox.q.y,
354 	      (int)tmp.subtype, tmp.Background_components,
355 	      (tmp.function_is_identity ? "no TR" :
356 	       "has TR"));
357     if (dev_proc(pdev, begin_transparency_mask) != 0)
358 	return (*dev_proc(pdev, begin_transparency_mask))
359 	    		(pdev, &tmp, &(pparams->bbox), pis, NULL, NULL);
360     else
361 	return 0;
362 }
363 
364 int
gs_end_transparency_mask(gs_state * pgs,gs_transparency_channel_selector_t csel)365 gs_end_transparency_mask(gs_state *pgs,
366 			 gs_transparency_channel_selector_t csel)
367 {
368     gs_pdf14trans_params_t params = { 0 };
369 
370     if_debug2('v', "[v](0x%lx)end_transparency_mask(%d)\n", (ulong)pgs,
371 	      (int)csel);
372 
373     params.pdf14_op = PDF14_END_TRANS_MASK;  /* Other parameters not used */
374     params.csel = csel;
375     return gs_state_update_pdf14trans(pgs, &params);
376 }
377 
378 int
gx_end_transparency_mask(gs_imager_state * pis,gx_device * pdev,const gs_pdf14trans_params_t * pparams)379 gx_end_transparency_mask(gs_imager_state * pis, gx_device * pdev,
380 				const gs_pdf14trans_params_t * pparams)
381 {
382     if (dev_proc(pdev, end_transparency_mask) != 0)
383 	return (*dev_proc(pdev, end_transparency_mask)) (pdev, NULL);
384     else
385 	return 0;
386 }
387 
388 int
gs_discard_transparency_layer(gs_state * pgs)389 gs_discard_transparency_layer(gs_state *pgs)
390 {
391     /****** NYI, DUMMY ******/
392     gs_transparency_state_t *pts = pgs->transparency_stack;
393 
394     if_debug1('v', "[v](0x%lx)discard_transparency_layer\n", (ulong)pgs);
395     if (!pts)
396 	return_error(gs_error_rangecheck);
397     pop_transparency_stack(pgs, "gs_discard_transparency_layer");
398     return 0;
399 }
400 
401 int
gs_init_transparency_mask(gs_state * pgs,gs_transparency_channel_selector_t csel)402 gs_init_transparency_mask(gs_state *pgs,
403 			  gs_transparency_channel_selector_t csel)
404 {
405     gs_pdf14trans_params_t params = { 0 };
406 
407     if_debug2('v', "[v](0x%lx)init_transparency_mask(%d)\n", (ulong)pgs,
408 	      (int)csel);
409 
410     params.pdf14_op = PDF14_INIT_TRANS_MASK;
411     params.csel = csel;
412     return gs_state_update_pdf14trans(pgs, &params);
413 }
414 
415 int
gx_init_transparency_mask(gs_imager_state * pis,const gs_pdf14trans_params_t * pparams)416 gx_init_transparency_mask(gs_imager_state * pis,
417 				const gs_pdf14trans_params_t * pparams)
418 {
419     gs_transparency_source_t *ptm;
420 
421     if_debug2('v', "[v](0x%lx)init_transparency_mask(%d)\n", (ulong)pis,
422 	      (int)pparams->csel);
423     switch (pparams->csel) {
424     case TRANSPARENCY_CHANNEL_Opacity: ptm = &pis->opacity; break;
425     case TRANSPARENCY_CHANNEL_Shape: ptm = &pis->shape; break;
426     default: return_error(gs_error_rangecheck);
427     }
428     rc_decrement_only(ptm->mask, "gs_init_transparency_mask");
429     ptm->mask = 0;
430     return 0;
431 }
432 
433 int
gs_push_pdf14trans_device(gs_state * pgs)434 gs_push_pdf14trans_device(gs_state * pgs)
435 {
436     gs_pdf14trans_params_t params = { 0 };
437 
438     params.pdf14_op = PDF14_PUSH_DEVICE;  /* Other parameters not used */
439     return gs_state_update_pdf14trans(pgs, &params);
440 }
441 
442 int
gs_pop_pdf14trans_device(gs_state * pgs)443 gs_pop_pdf14trans_device(gs_state * pgs)
444 {
445     gs_pdf14trans_params_t params = { 0 };
446 
447     params.pdf14_op = PDF14_POP_DEVICE;  /* Other parameters not used */
448     return gs_state_update_pdf14trans(pgs, &params);
449 }
450