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, ¶ms);
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, ¶ms);
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, ¶ms);
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, ¶ms);
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, ¶ms);
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, ¶ms);
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, ¶ms);
449 }
450