Coverage Report

Created: 2022-10-31 07:00

/src/ghostpdl/devices/vector/gdevpdft.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2022 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  1305 Grant Avenue - Suite 200, Novato,
13
   CA 94945, U.S.A., +1(415)492-9861, for further information.
14
*/
15
16
17
/* transparency processing for PDF-writing driver */
18
#include "gx.h"
19
#include "string_.h"
20
#include "gserrors.h"
21
#include "gstrans.h"
22
#include "gscolor2.h"
23
#include "gzstate.h"
24
#include "gdevpdfx.h"
25
#include "gdevpdfg.h"
26
#include "gdevpdfo.h"
27
#include "gsccolor.h"
28
29
static int
30
pdf_make_soft_mask_dict(gx_device_pdf * pdev, const gs_pdf14trans_params_t * pparams)
31
56
{
32
56
    pdf_resource_t *pres_soft_mask_dict = 0;
33
56
    cos_dict_t *soft_mask_dict;
34
56
    int code;
35
36
    /* Fixme : merge redundant objects. */
37
56
    code = pdf_alloc_resource(pdev, resourceSoftMaskDict, gs_no_id, &pres_soft_mask_dict, -1);
38
56
    if (code < 0)
39
0
        return code;
40
56
    cos_become(pres_soft_mask_dict->object, cos_type_dict);
41
56
    pdev->pres_soft_mask_dict = pres_soft_mask_dict;
42
56
    soft_mask_dict = (cos_dict_t *)pres_soft_mask_dict->object;
43
56
    code = cos_dict_put_c_key_string(soft_mask_dict, "/S",
44
56
            pparams->subtype == TRANSPARENCY_MASK_Alpha ? (byte *)"/Alpha" : (byte *)"/Luminosity",
45
56
            pparams->subtype == TRANSPARENCY_MASK_Alpha ? 6 : 11);
46
56
    if (code < 0)
47
0
        return code;
48
56
    if (pparams->Background_components) {
49
44
        cos_array_t *Background;
50
51
44
        Background = cos_array_from_floats(pdev, pparams->Background,
52
44
                    pparams->Background_components, "pdf_write_soft_mask_dict");
53
44
        if (Background == NULL)
54
0
            return_error(gs_error_VMerror);
55
44
        code = cos_dict_put_c_key_object(soft_mask_dict, "/BC", (cos_object_t *)Background);
56
44
        if (code < 0)
57
0
            return code;
58
44
    }
59
56
    if (pdev->CompatibilityLevel <= 1.7 && pparams->transfer_function != NULL && pdev->params.TransferFunctionInfo == tfi_Preserve) {
60
12
        long id;
61
12
        char buf[20];
62
63
12
        code = pdf_write_function(pdev, pparams->transfer_function, &id);
64
12
        if (code < 0)
65
0
            return code;
66
12
        gs_snprintf(buf, sizeof(buf), " %ld 0 R", id);
67
12
        code = cos_dict_put_c_key_string(soft_mask_dict, "/TR", (const byte *)buf, strlen(buf));
68
12
        if (code < 0)
69
0
            return code;
70
12
    }
71
56
    return 0;
72
73
56
}
74
75
static int
76
pdf_make_group_dict(gx_device_pdf * pdev, const gs_pdf14trans_params_t * pparams,
77
                            const gs_gstate * pgs, cos_dict_t **pdict)
78
963
{
79
963
    pdf_resource_t *pres_group;
80
963
    cos_dict_t *group_dict;
81
963
    int code;
82
963
    cos_value_t cs_value;
83
84
963
    code = pdf_alloc_resource(pdev, resourceGroup, gs_no_id, &pres_group, -1);
85
963
    if (code < 0)
86
0
        return code;
87
963
    cos_become(pres_group->object, cos_type_dict);
88
963
    group_dict = (cos_dict_t *)pres_group->object;
89
963
    code = cos_dict_put_c_key_string(group_dict, "/Type", (const byte *)"/Group", 6);
90
963
    if (code < 0)
91
0
        return code;
92
963
    code = cos_dict_put_c_key_string(group_dict, "/S", (const byte *)"/Transparency", 13);
93
963
    if (code < 0)
94
0
        return code;
95
963
    if (pparams->Isolated) {
96
622
        code = cos_dict_put_c_key_bool(group_dict, "/I", true);
97
622
        if (code < 0)
98
0
            return code;
99
622
    }
100
963
    if (pparams->Knockout) {
101
2
        code = cos_dict_put_c_key_bool(group_dict, "/K", true);
102
2
        if (code < 0)
103
0
            return code;
104
2
    }
105
    /* Note that we should not add in the graphic state
106
       color space for the group color if there was not
107
       a group color specified.
108
       In this case, the parent group is inherited from
109
       the previous group or the device color space */
110
963
    if (pgs != NULL && pparams->group_color_type != UNKNOWN) {
111
172
        const gs_color_space *cs = gs_currentcolorspace_inline(pgs);
112
113
172
        if (pparams->ColorSpace == NULL)
114
0
            code = pdf_color_space_named(pdev, pgs, &cs_value, NULL, cs,
115
0
                    &pdf_color_space_names, false, NULL, 0, false);
116
172
        else
117
172
            code = pdf_color_space_named(pdev, pgs, &cs_value, NULL, pparams->ColorSpace,
118
172
                    &pdf_color_space_names, false, NULL, 0, false);
119
172
        if (code < 0)
120
0
            return code;
121
172
        code = cos_dict_put_c_key(group_dict, "/CS", &cs_value);
122
172
        if (code < 0)
123
0
            return code;
124
172
    }
125
963
    group_dict = NULL; /* The next line invalidates it. */
126
963
    code = pdf_substitute_resource(pdev, &pres_group, resourceGroup, NULL, false);
127
963
    if (code < 0)
128
0
        return code;
129
963
    pres_group->where_used |= pdev->used_mask;
130
963
    *pdict = (cos_dict_t *)pres_group->object;
131
963
    return 0;
132
963
}
133
134
static int
135
pdf_make_form_dict(gx_device_pdf * pdev, const gs_pdf14trans_params_t * pparams,
136
                            const gs_gstate * pgs,
137
                            const cos_dict_t *group_dict, cos_dict_t *form_dict)
138
429
{
139
429
    cos_array_t *bbox_array;
140
429
    float bbox[4];
141
429
    gs_rect bbox_rect;
142
429
    int code;
143
144
429
    code = gs_bbox_transform(&pparams->bbox, &ctm_only(pgs), &bbox_rect);
145
429
    if (code < 0)
146
0
        return code;
147
429
    bbox[0] = bbox_rect.p.x;
148
429
    bbox[1] = bbox_rect.p.y;
149
429
    bbox[2] = bbox_rect.q.x;
150
429
    bbox[3] = bbox_rect.q.y;
151
429
    code = cos_dict_put_c_key_string(form_dict, "/Type", (const byte *)"/XObject", 8);
152
429
    if (code < 0)
153
0
        return code;
154
429
    code = cos_dict_put_c_key_string(form_dict, "/Subtype", (const byte *)"/Form", 5);
155
429
    if (code < 0)
156
0
        return code;
157
429
    code = cos_dict_put_c_key_int(form_dict, "/FormType", 1);
158
429
    if (code < 0)
159
0
        return code;
160
429
    code = cos_dict_put_c_key_string(form_dict, "/Matrix", (const byte *)"[1 0 0 1 0 0]", 13);
161
429
    if (code < 0)
162
0
        return code;
163
429
    bbox_array = cos_array_from_floats(pdev, bbox, 4, "pdf_begin_transparency_group");
164
429
    if (bbox_array == NULL)
165
0
        return_error(gs_error_VMerror);
166
429
    code = cos_dict_put_c_key_object(form_dict, "/BBox", (cos_object_t *)bbox_array);
167
429
    if (code < 0)
168
0
        return code;
169
429
    return cos_dict_put_c_key_object(form_dict, "/Group", (cos_object_t *)group_dict);
170
429
}
171
172
static int
173
pdf_begin_transparency_group(gs_gstate * pgs, gx_device_pdf * pdev,
174
                                const gs_pdf14trans_params_t * pparams, bool page_group)
175
963
{
176
963
    cos_dict_t *group_dict;
177
963
    int code;
178
179
963
    if (pgs == NULL)
180
0
        return_error(gs_error_unregistered); /* Must not happen. */
181
963
    code = pdf_make_group_dict(pdev, pparams, pgs, &group_dict);
182
963
    if (code < 0)
183
0
        return code;
184
963
    code = pdf_open_page(pdev, PDF_IN_STREAM);
185
963
    if (code < 0)
186
0
        return code;
187
963
    code = pdf_check_soft_mask(pdev, pgs);
188
963
    if (code < 0)
189
0
        return code;
190
963
    if (pdf_must_put_clip_path(pdev, pgs->clip_path)) {
191
323
        code = pdf_put_clip_path(pdev, pgs->clip_path);
192
323
        if (code < 0)
193
0
            return code;
194
323
    }
195
963
    if (page_group)
196
56
        pdev->pages[pdev->next_page].group_id = group_dict->id;
197
907
    else if (pparams->image_with_SMask) {
198
        /* An internal group for the image implementation.
199
           See doimagesmask in gs/lib/pdf_draw.ps .
200
           Just set a flag for skipping pdf_end_transparency_group. */
201
478
        pdev->image_with_SMask |= 1 << ++pdev->FormDepth;
202
478
        pdev->PatternsSinceForm = 0;
203
478
    } else {
204
429
        pdf_resource_t *pres, *pres_gstate = NULL;
205
429
        cos_dict_t *pcd = NULL, *pcd_Resources = NULL;
206
207
429
        code = pdf_prepare_drawing(pdev, pgs, &pres_gstate, false);
208
429
        if (code < 0)
209
0
            return code;
210
429
        code = pdf_end_gstate(pdev, pres_gstate);
211
429
        if (code < 0)
212
0
            return code;
213
429
        code = pdf_enter_substream(pdev, resourceXObject,
214
429
                gs_no_id, &pres, false, pdev->params.CompressPages);
215
429
        if (code < 0)
216
0
            return code;
217
429
        pdev->FormDepth++;
218
429
        pdev->PatternsSinceForm = 0;
219
429
        code = pdf_make_form_dict(pdev, pparams, pgs, group_dict, (cos_dict_t *)pres->object);
220
429
        if (code < 0)
221
0
            return code;
222
223
        /* Create a Resources dictionary and add it to the form dictionary */
224
429
        pcd = cos_stream_dict((cos_stream_t *)pres->object);
225
429
        pcd_Resources = cos_dict_alloc(pdev, "pdf_group(Resources)");
226
429
        if (pcd == NULL || pcd_Resources == NULL)
227
0
            return_error(gs_error_VMerror);
228
429
        code = cos_dict_put_c_key_object(pcd, "/Resources", COS_OBJECT(pcd_Resources));
229
429
        pdev->substream_Resources = pcd_Resources;
230
429
        return code;
231
429
    }
232
534
    return 0;
233
963
}
234
235
static int
236
pdf_end_transparency_group(gs_gstate * pgs, gx_device_pdf * pdev)
237
903
{
238
903
    int bottom = (pdev->ResourcesBeforeUsage ? 1 : 0);
239
240
903
    if (!is_in_page(pdev) && pdev->sbstack_depth == 0)
241
0
        return 0; /* A Group definition at the page level, handled separately. */
242
903
    if (pdev->image_with_SMask & (1 << pdev->FormDepth)) {
243
        /* An internal group for the image implementation.
244
           See pdf_begin_transparency_group. */
245
478
        pdev->image_with_SMask &= ~(1 << pdev->FormDepth--);
246
478
        pdev->PatternsSinceForm = 0;
247
478
        return 0;
248
478
    } else if (pdev->sbstack_depth == bottom) {
249
        /* We're closing the page group. */
250
56
        if (pdev->pages[pdev->next_page].group_id == 0)
251
0
            return_error(gs_error_unregistered); /* Must not happen. */
252
56
        return 0;
253
369
    } else {
254
369
        pdf_resource_t *pres = pdev->accumulating_substream_resource;
255
369
        int code;
256
369
        uint ignore;
257
258
369
        pdev->FormDepth--;
259
369
        pdev->PatternsSinceForm = 0;
260
369
        code = pdf_exit_substream(pdev);
261
369
        if (code < 0)
262
0
            return code;
263
369
        code = pdf_substitute_resource(pdev, &pres, resourceXObject, NULL, false);
264
369
        if (code < 0)
265
0
            return code;
266
        /* We need to update the 'where_used' field, in case we substituted a resource */
267
369
        pres->where_used |= pdev->used_mask;
268
369
        sputc(pdev->strm,'/');
269
369
        sputs(pdev->strm, (const byte *)pres->rname, strlen(pres->rname), &ignore);
270
369
        sputs(pdev->strm, (const byte *)" Do\n", 4, &ignore);
271
369
        code = pdf_add_resource(pdev, pdev->substream_Resources, "/XObject", pres);
272
369
        return code;
273
369
    }
274
903
}
275
276
static int
277
pdf_begin_transparency_mask(gs_gstate * pgs, gx_device_pdf * pdev,
278
                                const gs_pdf14trans_params_t * pparams)
279
150
{
280
150
    if (pparams->subtype == TRANSPARENCY_MASK_None) {
281
94
        int code;
282
94
        pdf_resource_t *pres = 0L;
283
284
        /* reset the soft mask ID. Apparently this is only used by pdfwrite, if we don't
285
         * reset it, then the pdf_prepare_drawing code doesn't know that the SMask has
286
         * changed, and so doesn't write out the GState
287
         */
288
94
        pgs->soft_mask_id = 0;
289
94
        code = pdf_prepare_drawing(pdev, pgs, &pres, false);
290
94
        if (code == gs_error_interrupt) {
291
            /* */
292
            /* Not in an appropriate context.  Do not restore the soft_mask_id.
293
               Otherwise any group push that occurs following this will use that
294
               softmask, which clearly should be NONE here.
295
             */
296
            /* ignore return code, we don't care about this graphics state as we aren't
297
             * emitting it anyway
298
             */
299
20
            pdf_end_gstate(pdev, pres);
300
20
            return 0;
301
20
        }
302
74
        if (code < 0)
303
0
            return code;
304
74
        code = pdf_end_gstate(pdev, pres);
305
74
        if (code < 0)
306
0
            return code;
307
74
        return 0;
308
74
    }
309
56
    if (pparams->mask_is_image) {
310
        /* HACK :
311
            The control comes here when
312
            the PDF interpreter will make the PS interpreter
313
            to interprete the mask for filling the transparency buffer
314
            with an SMask image.
315
            Since we handle Type 3 images as a high level objects,
316
            we don't install the transparency buffer here
317
            and need to skip the image enumeration for the SMask.
318
            However we have no right method for skipping
319
            an image enumeration due to possible side effect
320
            of the image data proc in Postscript language.
321
            Therefore we do enumerate the image mask and accumulate
322
            it as a PDF stream, but don't create a reference to it.
323
            Later it will be enumerated once again as a part of SMask-ed image,
324
            and the pdfwrite image handler will recognize duplicated images
325
            and won't create the second stream for same image.
326
327
            We could make a special workaround for
328
            skipping mask images either in the graphics library or
329
            in the PS code of the PDF interpreter,
330
            but we don't want to complicate things now.
331
            The performance leak for the second enumeration
332
            shouldn't be harmful.
333
334
            So now just set a flag for pdf_end_and_do_image.
335
        */
336
0
        pdev->image_mask_skip = true;
337
0
        return 0;
338
56
    } else {
339
56
        int code;
340
341
56
        pdev->smask_construction = true;
342
56
        code = pdf_make_soft_mask_dict(pdev, pparams);
343
56
        if (code < 0)
344
0
            return code;
345
56
        code = pdf_open_page(pdev, PDF_IN_STREAM);
346
56
        if (code < 0)
347
0
            return code;
348
56
        return pdf_begin_transparency_group(pgs, pdev, pparams, 0);
349
56
    }
350
56
}
351
352
static int
353
pdf_end_transparency_mask(gs_gstate * pgs, gx_device_pdf * pdev,
354
                                const gs_pdf14trans_params_t * pparams)
355
56
{
356
56
    pdev->smask_construction = false;
357
56
    if (pdev->image_mask_skip)
358
0
        pdev->image_mask_skip = false;
359
56
    else {
360
56
        pdf_resource_t *pres = pdev->accumulating_substream_resource;
361
56
        int code;
362
56
        char buf[20];
363
364
56
        code = pdf_exit_substream(pdev);
365
56
        if (code < 0)
366
0
            return code;
367
56
        code = pdf_substitute_resource(pdev, &pres, resourceXObject, NULL, false);
368
56
        if (code < 0)
369
0
            return 0;
370
        /* We need to update the 'where_used' field, in case we substituted a resource */
371
56
        pres->where_used |= pdev->used_mask;
372
56
        gs_snprintf(buf, sizeof(buf), "%ld 0 R", pdf_resource_id(pres));
373
56
        if (pdev->pres_soft_mask_dict == 0L) {
374
            /* something went horribly wrong, we have an 'end' wihtout a matching 'begin'
375
             * Give up, throw an error.
376
             */
377
0
            return_error(gs_error_undefined);
378
0
        }
379
56
        code = cos_dict_put_c_key_string((cos_dict_t *)pdev->pres_soft_mask_dict->object,
380
56
                "/G", (const byte *)buf, strlen(buf));
381
56
        if (code < 0)
382
0
            return code;
383
56
        code = pdf_substitute_resource(pdev, &pdev->pres_soft_mask_dict,
384
56
                                        resourceSoftMaskDict, NULL, false);
385
56
        if (code < 0)
386
0
            return code;
387
56
        pdev->pres_soft_mask_dict->where_used |= pdev->used_mask;
388
56
        pgs->soft_mask_id = pdev->pres_soft_mask_dict->object->id;
389
56
        pdev->pres_soft_mask_dict = NULL;
390
        /* We called pdf_start_trnasparency_group (see pdf_begin_transparency_mask
391
         * above) but we don't call pdf_end_transparency_group, so we must reduce
392
         * the FormDepth ourselves.
393
         */
394
56
        pdev->FormDepth--;
395
56
        pdev->PatternsSinceForm = 0;
396
56
    }
397
56
    return 0;
398
56
}
399
400
static int
401
pdf_set_blend_params(gs_gstate * pgs, gx_device_pdf * dev,
402
                                const gs_pdf14trans_params_t * pparams)
403
0
{
404
0
    return 0;
405
0
}
406
407
int
408
gdev_pdf_composite(gx_device *dev,
409
    gx_device **pcdev, const gs_composite_t *pct,
410
    gs_gstate *pgs, gs_memory_t *memory, gx_device *cdev)
411
21.3k
{
412
21.3k
    gx_device_pdf *pdev = (gx_device_pdf *)dev;
413
414
21.3k
    if (pdev->HaveTransparency && pdev->CompatibilityLevel >= 1.4 &&
415
21.3k
            pct->type->comp_id == GX_COMPOSITOR_PDF14_TRANS &&
416
21.3k
            pdev->PDFA != 1) {
417
13.5k
        gs_pdf14trans_t *pcte = (gs_pdf14trans_t *)pct;
418
13.5k
        gs_pdf14trans_params_t *params = &pcte->params;
419
420
13.5k
        *pcdev = dev;
421
13.5k
        switch(params->pdf14_op) {
422
158
            case PDF14_PUSH_DEVICE:
423
158
                return 0;
424
158
            case PDF14_POP_DEVICE:
425
158
                return 0;
426
0
            case PDF14_ABORT_DEVICE:
427
0
                return 0;
428
56
            case PDF14_BEGIN_TRANS_PAGE_GROUP:
429
56
                return pdf_begin_transparency_group(pgs, pdev, params, 1);
430
851
            case PDF14_BEGIN_TRANS_GROUP:
431
851
                return pdf_begin_transparency_group(pgs, pdev, params, 0);
432
903
            case PDF14_END_TRANS_GROUP:
433
903
                return pdf_end_transparency_group(pgs, pdev);
434
5.43k
            case PDF14_BEGIN_TRANS_TEXT_GROUP:
435
5.43k
                return 0;
436
5.59k
            case PDF14_END_TRANS_TEXT_GROUP:
437
5.59k
                return 0;
438
150
            case PDF14_BEGIN_TRANS_MASK:
439
150
                return pdf_begin_transparency_mask(pgs, pdev, params);
440
56
            case PDF14_END_TRANS_MASK:
441
56
                return pdf_end_transparency_mask(pgs, pdev, params);
442
0
            case PDF14_SET_BLEND_PARAMS:
443
0
                return pdf_set_blend_params(pgs, pdev, params);
444
0
            case PDF14_PUSH_TRANS_STATE:
445
0
                return 0;
446
41
            case PDF14_POP_TRANS_STATE:
447
41
                return 0;
448
56
            case PDF14_PUSH_SMASK_COLOR:
449
56
                return 0;
450
56
            case PDF14_POP_SMASK_COLOR:
451
56
                return 0;
452
453
0
            default :
454
0
                return_error(gs_error_unregistered); /* Must not happen. */
455
13.5k
        }
456
0
        return 0;
457
13.5k
    }
458
7.81k
    return psdf_composite(dev, pcdev, pct, pgs, memory, cdev);
459
21.3k
}
460
461
/* We're not sure why the folllowing device methods are never called.
462
   Stub them for a while. */
463
464
int
465
gdev_pdf_begin_transparency_group(gx_device *dev,
466
    const gs_transparency_group_params_t *ptgp,
467
    const gs_rect *pbbox,
468
    gs_gstate *pgs, gs_memory_t *mem)
469
0
{
470
0
    return 0;
471
0
}
472
473
int
474
gdev_pdf_end_transparency_group(gx_device *dev,
475
    gs_gstate *pgs)
476
0
{
477
0
    return 0;
478
0
}
479
480
int
481
gdev_pdf_begin_transparency_mask(gx_device *dev,
482
    const gx_transparency_mask_params_t *ptmp,
483
    const gs_rect *pbbox,
484
    gs_gstate *pgs, gs_memory_t *mem)
485
0
{
486
0
    return 0;
487
0
}
488
489
int
490
gdev_pdf_end_transparency_mask(gx_device *dev,
491
    gs_gstate *pgs)
492
0
{
493
0
    return 0;
494
0
}