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 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 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 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 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 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 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 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 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 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 return 0; 353 } 354 return psdf_create_compositor(dev, pcdev, pct, pis, memory); 355 } 356 357 /* We're not sure why the folllowing device methods are never called. 358 Stub them for a while. */ 359 360 int 361 gdev_pdf_begin_transparency_group(gx_device *dev, 362 const gs_transparency_group_params_t *ptgp, 363 const gs_rect *pbbox, 364 gs_imager_state *pis, 365 gs_transparency_state_t **ppts, 366 gs_memory_t *mem) 367 { 368 return 0; 369 } 370 371 int 372 gdev_pdf_end_transparency_group(gx_device *dev, 373 gs_imager_state *pis, 374 gs_transparency_state_t **ppts) 375 { 376 return 0; 377 } 378 379 int 380 gdev_pdf_begin_transparency_mask(gx_device *dev, 381 const gx_transparency_mask_params_t *ptmp, 382 const gs_rect *pbbox, 383 gs_imager_state *pis, 384 gs_transparency_state_t **ppts, 385 gs_memory_t *mem) 386 { 387 return 0; 388 } 389 390 int 391 gdev_pdf_end_transparency_mask(gx_device *dev, 392 gs_transparency_mask_t **pptm) 393 { 394 return 0; 395 } 396 397 int 398 gdev_pdf_discard_transparency_layer(gx_device *dev, 399 gs_transparency_state_t **ppts) 400 { 401 return 0; 402 } 403