1 /* Copyright (C) 1996, 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: gdevpdft.c,v 1.52 2005/09/06 22:21:14 leonardo Exp $ */
18 /* transparency processing for PDF-writing driver */
19 #include "gx.h"
20 #include "string_.h"
21 #include "gserrors.h"
22 #include "gstrans.h"
23 #include "gscolor2.h"
24 #include "gzstate.h"
25 #include "gdevpdfx.h"
26 #include "gdevpdfg.h"
27 #include "gdevpdfo.h"
28
29 private int
pdf_make_soft_mask_dict(gx_device_pdf * pdev,const gs_pdf14trans_params_t * pparams)30 pdf_make_soft_mask_dict(gx_device_pdf * pdev, const gs_pdf14trans_params_t * pparams)
31 {
32 pdf_resource_t *pres_soft_mask_dict = 0;
33 cos_dict_t *soft_mask_dict;
34 int code;
35
36 /* Fixme : merge redundant objects. */
37 code = pdf_alloc_resource(pdev, resourceSoftMaskDict, gs_no_id, &pres_soft_mask_dict, -1);
38 if (code < 0)
39 return code;
40 cos_become(pres_soft_mask_dict->object, cos_type_dict);
41 pdev->pres_soft_mask_dict = pres_soft_mask_dict;
42 soft_mask_dict = (cos_dict_t *)pres_soft_mask_dict->object;
43 code = cos_dict_put_c_key_string(soft_mask_dict, "/S",
44 pparams->subtype == TRANSPARENCY_MASK_Alpha ? (byte *)"/Alpha" : (byte *)"/Luminosity",
45 pparams->subtype == TRANSPARENCY_MASK_Alpha ? 6 : 11);
46 if (code < 0)
47 return code;
48 if (pparams->Background_components) {
49 cos_array_t *Background;
50
51 Background = cos_array_from_floats(pdev, pparams->Background,
52 pparams->Background_components, "pdf_write_soft_mask_dict");
53 if (Background == NULL)
54 return_error(gs_error_VMerror);
55 code = cos_dict_put_c_key_object(soft_mask_dict, "/BC", (cos_object_t *)Background);
56 if (code < 0)
57 return code;
58 }
59 if (pparams->transfer_function != NULL) {
60 long id;
61 char buf[20];
62
63 code = pdf_write_function(pdev, pparams->transfer_function, &id);
64 if (code < 0)
65 return code;
66 sprintf(buf, " %ld 0 R", id);
67 code = cos_dict_put_c_key_string(soft_mask_dict, "/TR", (const byte *)buf, strlen(buf));
68 if (code < 0)
69 return code;
70 }
71 return 0;
72
73 }
74
75 private int
pdf_make_group_dict(gx_device_pdf * pdev,const gs_pdf14trans_params_t * pparams,const gs_imager_state * pis,cos_dict_t ** pdict)76 pdf_make_group_dict(gx_device_pdf * pdev, const gs_pdf14trans_params_t * pparams,
77 const gs_imager_state * pis, cos_dict_t **pdict)
78 {
79 pdf_resource_t *pres_group;
80 cos_dict_t *group_dict;
81 int code;
82 const gs_state *gstate = gx_hld_get_gstate_ptr(pis);
83 cos_value_t cs_value;
84
85 code = pdf_alloc_resource(pdev, resourceGroup, gs_no_id, &pres_group, -1);
86 if (code < 0)
87 return code;
88 cos_become(pres_group->object, cos_type_dict);
89 group_dict = (cos_dict_t *)pres_group->object;
90 code = cos_dict_put_c_key_string(group_dict, "/Type", (const byte *)"/Group", 6);
91 if (code < 0)
92 return code;
93 code = cos_dict_put_c_key_string(group_dict, "/S", (const byte *)"/Transparency", 13);
94 if (code < 0)
95 return code;
96 if (pparams->Isolated) {
97 code = cos_dict_put_c_key_bool(group_dict, "/I", true);
98 if (code < 0)
99 return code;
100 }
101 if (pparams->Knockout) {
102 code = cos_dict_put_c_key_bool(group_dict, "/K", true);
103 if (code < 0)
104 return code;
105 }
106 if (gstate != NULL) {
107 const gs_color_space *cs = gstate->color_space;
108
109 code = pdf_color_space(pdev, &cs_value, NULL, cs,
110 &pdf_color_space_names, false);
111 if (code < 0)
112 return code;
113 code = cos_dict_put_c_key(group_dict, "/CS", &cs_value);
114 if (code < 0)
115 return code;
116 }
117 group_dict = NULL; /* The next line invalidates it. */
118 code = pdf_substitute_resource(pdev, &pres_group, resourceGroup, NULL, false);
119 if (code < 0)
120 return code;
121 *pdict = (cos_dict_t *)pres_group->object;
122 return 0;
123 }
124
125 private int
pdf_make_form_dict(gx_device_pdf * pdev,const gs_pdf14trans_params_t * pparams,const gs_imager_state * pis,const cos_dict_t * group_dict,cos_dict_t * form_dict)126 pdf_make_form_dict(gx_device_pdf * pdev, const gs_pdf14trans_params_t * pparams,
127 const gs_imager_state * pis,
128 const cos_dict_t *group_dict, cos_dict_t *form_dict)
129 {
130 cos_array_t *bbox_array;
131 float bbox[4];
132 gs_rect bbox_rect;
133 int code;
134
135
136 code = gs_bbox_transform(&pparams->bbox, &ctm_only(pis), &bbox_rect);
137 if (code < 0)
138 return code;
139 bbox[0] = bbox_rect.p.x;
140 bbox[1] = bbox_rect.p.y;
141 bbox[2] = bbox_rect.q.x;
142 bbox[3] = bbox_rect.q.y;
143 code = cos_dict_put_c_key_string(form_dict, "/Type", (const byte *)"/XObject", 8);
144 if (code < 0)
145 return code;
146 code = cos_dict_put_c_key_string(form_dict, "/Subtype", (const byte *)"/Form", 5);
147 if (code < 0)
148 return code;
149 code = cos_dict_put_c_key_int(form_dict, "/FormType", 1);
150 if (code < 0)
151 return code;
152 code = cos_dict_put_c_key_string(form_dict, "/Matrix", (const byte *)"[1 0 0 1 0 0]", 13);
153 if (code < 0)
154 return code;
155 bbox_array = cos_array_from_floats(pdev, bbox, 4, "pdf_begin_transparency_group");
156 if (bbox_array == NULL)
157 return_error(gs_error_VMerror);
158 code = cos_dict_put_c_key_object(form_dict, "/BBox", (cos_object_t *)bbox_array);
159 if (code < 0)
160 return code;
161 return cos_dict_put_c_key_object(form_dict, "/Group", (cos_object_t *)group_dict);
162 }
163
164 private int
pdf_begin_transparency_group(gs_imager_state * pis,gx_device_pdf * pdev,const gs_pdf14trans_params_t * pparams)165 pdf_begin_transparency_group(gs_imager_state * pis, gx_device_pdf * pdev,
166 const gs_pdf14trans_params_t * pparams)
167 {
168 cos_dict_t *group_dict;
169 bool in_page = is_in_page(pdev);
170 const gs_state *gstate = gx_hld_get_gstate_ptr(pis);
171 int code;
172
173 if (gstate == NULL)
174 return_error(gs_error_unregistered); /* Must not happen. */
175 code = pdf_make_group_dict(pdev, pparams, pis, &group_dict);
176 if (code < 0)
177 return code;
178 code = pdf_open_page(pdev, PDF_IN_STREAM);
179 if (code < 0)
180 return code;
181 if (pdf_must_put_clip_path(pdev, gstate->clip_path)) {
182 code = pdf_put_clip_path(pdev, gstate->clip_path);
183 if (code < 0)
184 return code;
185 }
186 if (!in_page)
187 pdev->pages[pdev->next_page].group_id = group_dict->id;
188 else {
189 pdf_resource_t *pres, *pres_gstate = NULL;
190
191 code = pdf_prepare_drawing(pdev, pis, &pres_gstate);
192 if (code < 0)
193 return code;
194 code = pdf_end_gstate(pdev, pres_gstate);
195 if (code < 0)
196 return code;
197 code = pdf_enter_substream(pdev, resourceXObject,
198 gs_no_id, &pres, false, pdev->params.CompressPages);
199 if (code < 0)
200 return code;
201 return pdf_make_form_dict(pdev, pparams, pis, group_dict, (cos_dict_t *)pres->object);
202 }
203 return 0;
204 }
205
206 private int
pdf_end_transparency_group(gs_imager_state * pis,gx_device_pdf * pdev)207 pdf_end_transparency_group(gs_imager_state * pis, gx_device_pdf * pdev)
208 {
209 int bottom = (pdev->ResourcesBeforeUsage ? 1 : 0);
210
211 if (pdev->sbstack_depth == bottom) {
212 /* We're closing the page group. */
213 if (pdev->pages[pdev->next_page].group_id == 0)
214 return_error(gs_error_unregistered); /* Must not happen. */
215 return 0;
216 } else {
217 pdf_resource_t *pres = pdev->accumulating_substream_resource;
218 int code;
219 uint ignore;
220
221 code = pdf_exit_substream(pdev);
222 if (code < 0)
223 return code;
224 code = pdf_substitute_resource(pdev, &pres, resourceXObject, NULL, false);
225 if (code < 0)
226 return code;
227 sputc(pdev->strm,'/');
228 sputs(pdev->strm, (const byte *)pres->rname, strlen(pres->rname), &ignore);
229 sputs(pdev->strm, (const byte *)" Do\n", 4, &ignore);
230 return 0;
231 }
232 }
233
234 private int
pdf_begin_transparency_mask(gs_imager_state * pis,gx_device_pdf * pdev,const gs_pdf14trans_params_t * pparams)235 pdf_begin_transparency_mask(gs_imager_state * pis, gx_device_pdf * pdev,
236 const gs_pdf14trans_params_t * pparams)
237 {
238 if (pparams->mask_is_image) {
239 /* HACK :
240 The control comes here when
241 the PDF interpreter will make the PS interpreter
242 to interprete the mask for filling the transparency buffer
243 with an SMask image.
244 Since we handle Type 3 images as a high level objects,
245 we don't install the transparency buffer here
246 and need to skip the image enumeration for the SMask.
247 However we have no right method for skipping
248 an image enumeration due to possible side effect
249 of the image data proc in Postscript language.
250 Therefore we do enumerate the image mask and accumulate
251 it as a PDF stream, but don't create a reference to it.
252 Later it will be enumerated once again as a part of SMask-ed image,
253 and the pdfwrite image handler will recognize duplicated images
254 and won't create the second stream for same image.
255
256 We could make a special workaround for
257 skipping mask images either in the graphics library or
258 in the PS code of the PDF interpreter,
259 but we don't want to complicate things now.
260 The performance leak for the second enumeration
261 shouldn't be harmful.
262
263 So now just set a flag for pdf_end_and_do_image.
264 */
265 pdev->image_mask_skip = true;
266 return 0;
267 } else {
268 int code;
269
270 code = pdf_make_soft_mask_dict(pdev, pparams);
271 if (code < 0)
272 return code;
273 code = pdf_open_page(pdev, PDF_IN_STREAM);
274 if (code < 0)
275 return code;
276 return pdf_begin_transparency_group(pis, pdev, pparams);
277 }
278 }
279
280 private int
pdf_end_transparency_mask(gs_imager_state * pis,gx_device_pdf * pdev,const gs_pdf14trans_params_t * pparams)281 pdf_end_transparency_mask(gs_imager_state * pis, gx_device_pdf * pdev,
282 const gs_pdf14trans_params_t * pparams)
283 {
284 if (pdev->image_mask_skip)
285 pdev->image_mask_skip = false;
286 else {
287 pdf_resource_t *pres = pdev->accumulating_substream_resource;
288 int code;
289 char buf[20];
290
291 code = pdf_exit_substream(pdev);
292 if (code < 0)
293 return code;
294 code = pdf_substitute_resource(pdev, &pres, resourceXObject, NULL, false);
295 if (code < 0)
296 return 0;
297 sprintf(buf, "%ld 0 R", pdf_resource_id(pres));
298 code = cos_dict_put_c_key_string((cos_dict_t *)pdev->pres_soft_mask_dict->object,
299 "/G", (const byte *)buf, strlen(buf));
300 if (code < 0)
301 return code;
302 code = pdf_substitute_resource(pdev, &pdev->pres_soft_mask_dict,
303 resourceSoftMaskDict, NULL, false);
304 if (code < 0)
305 return code;
306 pis->soft_mask_id = pdev->pres_soft_mask_dict->object->id;
307 pdev->pres_soft_mask_dict = NULL;
308 }
309 return 0;
310 }
311
312 private int
pdf_set_blend_params(gs_imager_state * pis,gx_device_pdf * dev,const gs_pdf14trans_params_t * pparams)313 pdf_set_blend_params(gs_imager_state * pis, gx_device_pdf * dev,
314 const gs_pdf14trans_params_t * pparams)
315 {
316 return 0;
317 }
318
319 int
gdev_pdf_create_compositor(gx_device * dev,gx_device ** pcdev,const gs_composite_t * pct,gs_imager_state * pis,gs_memory_t * memory)320 gdev_pdf_create_compositor(gx_device *dev,
321 gx_device **pcdev, const gs_composite_t *pct,
322 gs_imager_state *pis, gs_memory_t *memory)
323 {
324 gx_device_pdf *pdev = (gx_device_pdf *)dev;
325
326 if (pdev->HaveTransparency && pdev->CompatibilityLevel >= 1.4 &&
327 pct->type->comp_id == GX_COMPOSITOR_PDF14_TRANS) {
328 gs_pdf14trans_t *pcte = (gs_pdf14trans_t *)pct;
329 gs_pdf14trans_params_t *params = &pcte->params;
330
331 *pcdev = dev;
332 switch(params->pdf14_op) {
333 case PDF14_PUSH_DEVICE:
334 return 0;
335 case PDF14_POP_DEVICE:
336 return 0;
337 case PDF14_BEGIN_TRANS_GROUP:
338 return pdf_begin_transparency_group(pis, pdev, params);
339 case PDF14_END_TRANS_GROUP:
340 return pdf_end_transparency_group(pis, pdev);
341 case PDF14_INIT_TRANS_MASK:
342 return gx_init_transparency_mask(pis, params);
343 case PDF14_BEGIN_TRANS_MASK:
344 return pdf_begin_transparency_mask(pis, pdev, params);
345 case PDF14_END_TRANS_MASK:
346 return pdf_end_transparency_mask(pis, pdev, params);
347 case PDF14_SET_BLEND_PARAMS:
348 return pdf_set_blend_params(pis, pdev, params);
349 default :
350 return_error(gs_error_unregistered); /* Must not happen. */
351 }
352 }
353 return psdf_create_compositor(dev, pcdev, pct, pis, memory);
354 }
355
356 /* We're not sure why the folllowing device methods are never called.
357 Stub them for a while. */
358
359 int
gdev_pdf_begin_transparency_group(gx_device * dev,const gs_transparency_group_params_t * ptgp,const gs_rect * pbbox,gs_imager_state * pis,gs_transparency_state_t ** ppts,gs_memory_t * mem)360 gdev_pdf_begin_transparency_group(gx_device *dev,
361 const gs_transparency_group_params_t *ptgp,
362 const gs_rect *pbbox,
363 gs_imager_state *pis,
364 gs_transparency_state_t **ppts,
365 gs_memory_t *mem)
366 {
367 return 0;
368 }
369
370 int
gdev_pdf_end_transparency_group(gx_device * dev,gs_imager_state * pis,gs_transparency_state_t ** ppts)371 gdev_pdf_end_transparency_group(gx_device *dev,
372 gs_imager_state *pis,
373 gs_transparency_state_t **ppts)
374 {
375 return 0;
376 }
377
378 int
gdev_pdf_begin_transparency_mask(gx_device * dev,const gx_transparency_mask_params_t * ptmp,const gs_rect * pbbox,gs_imager_state * pis,gs_transparency_state_t ** ppts,gs_memory_t * mem)379 gdev_pdf_begin_transparency_mask(gx_device *dev,
380 const gx_transparency_mask_params_t *ptmp,
381 const gs_rect *pbbox,
382 gs_imager_state *pis,
383 gs_transparency_state_t **ppts,
384 gs_memory_t *mem)
385 {
386 return 0;
387 }
388
389 int
gdev_pdf_end_transparency_mask(gx_device * dev,gs_transparency_mask_t ** pptm)390 gdev_pdf_end_transparency_mask(gx_device *dev,
391 gs_transparency_mask_t **pptm)
392 {
393 return 0;
394 }
395
396 int
gdev_pdf_discard_transparency_layer(gx_device * dev,gs_transparency_state_t ** ppts)397 gdev_pdf_discard_transparency_layer(gx_device *dev,
398 gs_transparency_state_t **ppts)
399 {
400 return 0;
401 }
402