Coverage Report

Created: 2026-02-14 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/pdf/pdf_trans.c
Line
Count
Source
1
/* Copyright (C) 2019-2025 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.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
16
/* Transparency support */
17
18
#include "pdf_int.h"
19
#include "pdf_stack.h"
20
#include "pdf_trans.h"
21
#include "pdf_dict.h"
22
#include "pdf_colour.h"
23
#include "pdf_font_types.h"
24
#include "pdf_gstate.h"
25
#include "pdf_array.h"
26
#include "pdf_image.h"
27
#include "pdf_device.h"
28
#include "pdf_misc.h"
29
#include "pdf_func.h"
30
31
#include "gstparam.h"
32
#include "gsicc_manage.h"       /* For gs_currentoverrideicc() */
33
#include "gscoord.h"            /* For gs_setmatrix()*/
34
#include "gsstate.h"            /* For gs_currentstrokeoverprint() and others */
35
#include "gspath.h"             /* For gs_clippath() */
36
#include "gsicc_cache.h"        /* For gsicc_profiles_equal() */
37
38
/* Implement the TransferFunction using a Function. */
39
static int
40
pdfi_tf_using_function(double in_val, float *out, void *proc_data)
41
87.8k
{
42
87.8k
    float in = in_val;
43
87.8k
    gs_function_t *const pfn = proc_data;
44
45
87.8k
    return gs_function_evaluate(pfn, &in, out);
46
87.8k
}
47
48
static void
49
pdfi_set_GrayBackground(gs_transparency_mask_params_t *params)
50
546
{
51
546
    float num;
52
546
    int i;
53
54
2.36k
    for (i = 0; i < params->Background_components; i++)
55
1.81k
    {
56
1.81k
        if (params->Background[i] < 0)
57
0
            params->Background[i] = 0;
58
1.81k
        else if (params->Background[i] > 1)
59
0
            params->Background[i] = 1;
60
1.81k
    }
61
62
    /* This uses definition from PLRM2 6.2.1 and 6.2.2 */
63
    /* TODO: We are assuming 3 components is RGB and 4 components is CMYK,
64
       which might not strictly be true?  But it provides a better
65
       estimated value than doing nothing.
66
    */
67
546
    switch(params->Background_components) {
68
26
    case 3:
69
        /* RGB: currentgray = 0.3*R + 0.59*G + 0.11*B */
70
26
        params->GrayBackground = (0.3 * params->Background[0] +
71
26
                                  0.59 * params->Background[1] +
72
26
                                  0.11 * params->Background[2]);
73
26
        break;
74
406
    case 4:
75
        /* CMYK: currentgray = 1.0 – min (1.0, .3*C + .59*M + .11*Y + K)
76
        */
77
406
        num = 0.3*params->Background[0] + 0.59*params->Background[1] +
78
406
            0.11*params->Background[2] + params->Background[3];
79
406
        params->GrayBackground = 1 - num;
80
406
        break;
81
114
    case 1:
82
114
        params->GrayBackground = params->Background[0];
83
114
        break;
84
0
    default:
85
        /* No clue... */
86
0
        params->GrayBackground = 0;
87
546
    }
88
546
    if (params->GrayBackground < 0)
89
400
        params->GrayBackground = 0;
90
146
    else if (params->GrayBackground > 1)
91
0
        params->GrayBackground = 1;
92
546
}
93
94
/* (see pdf_draw.ps/execmaskgroup) */
95
static int pdfi_trans_set_mask(pdf_context *ctx, pdfi_int_gstate *igs, int colorindex)
96
7.66k
{
97
7.66k
    int code = 0, code1 = 0;
98
7.66k
    pdf_dict *SMask = igs->SMask;
99
7.66k
    gs_color_space *pcs = NULL;
100
7.66k
    gs_rect bbox;
101
7.66k
    gs_transparency_mask_params_t params;
102
7.66k
    pdf_array *BBox = NULL;
103
7.66k
    pdf_array *Matrix = NULL;
104
7.66k
    pdf_array *a = NULL;
105
7.66k
    pdf_array *BC = NULL;
106
7.66k
    pdf_stream *G_stream = NULL;
107
7.66k
    pdf_dict *G_stream_dict = NULL;
108
7.66k
    pdf_dict *Group = NULL;
109
7.66k
    pdf_obj *TR = NULL;
110
7.66k
    gs_function_t *gsfunc = NULL;
111
7.66k
    pdf_name *n = NULL;
112
7.66k
    pdf_name *S = NULL;
113
7.66k
    pdf_obj *CS = NULL;
114
7.66k
    gs_matrix save_matrix, GroupMat, group_Matrix;
115
7.66k
    gs_transparency_mask_subtype_t subtype = TRANSPARENCY_MASK_Luminosity;
116
7.66k
    bool Processed, ProcessedKnown = 0;
117
7.66k
    bool save_OverrideICC = gs_currentoverrideicc(ctx->pgs);
118
7.66k
    gs_gstate *saved_gs = NULL;
119
7.66k
    gs_rect clip_bbox;
120
7.66k
    int empty = 0;
121
122
#if DEBUG_TRANSPARENCY
123
    dbgmprintf(ctx->memory, "pdfi_trans_set_mask (.execmaskgroup) BEGIN\n");
124
#endif
125
7.66k
    memset(&params, 0, sizeof(params));
126
127
    /* Following the logic of the ps code, cram a /Processed key in the SMask dict to
128
     * track whether it's already been processed.
129
     */
130
7.66k
    code = pdfi_dict_knownget_bool(ctx, SMask, "Processed", &Processed);
131
7.66k
    if (code > 0) {
132
4.53k
        if (Processed) {
133
#if DEBUG_TRANSPARENCY
134
          dbgmprintf(ctx->memory, "SMask already built, skipping\n");
135
#endif
136
932
          code = 0;
137
932
          goto exit;
138
932
        }
139
3.60k
        ProcessedKnown = 1;
140
3.60k
    }
141
142
6.72k
    gs_setoverrideicc(ctx->pgs, true);
143
144
    /* If /Processed not in the dict, put it there */
145
6.72k
    if (code == 0) {
146
3.12k
        code = pdfi_dict_put_bool(ctx, SMask, "Processed", false);
147
3.12k
        if (code < 0)
148
0
            goto exit;
149
3.12k
        ProcessedKnown = 1;
150
3.12k
    }
151
152
    /* See pdf1.7 pg 553 (pain in the butt to find this!) */
153
6.72k
    code = pdfi_dict_knownget_type(ctx, SMask, "Type", PDF_NAME, (pdf_obj **)&n);
154
6.72k
    if (code == 0 || (code > 0 && pdfi_name_is(n, "Mask"))) {
155
        /* G is transparency group XObject (required) */
156
6.69k
        code = pdfi_dict_knownget_type(ctx, SMask, "G", PDF_STREAM, (pdf_obj **)&G_stream);
157
6.69k
        if (code <= 0) {
158
3.63k
            pdfi_trans_end_smask_notify(ctx);
159
3.63k
            code = pdfi_set_error_stop(ctx, code, NULL, E_PDF_SMASK_MISSING_G, "pdfi_trans_set_mask", "");
160
3.63k
            goto exit;
161
3.63k
        }
162
163
3.06k
        code = pdfi_dict_from_obj(ctx, (pdf_obj *)G_stream, &G_stream_dict);
164
3.06k
        if (code < 0)
165
0
            goto exit;
166
167
        /* S is a subtype name (required) */
168
3.06k
        code = pdfi_dict_knownget_type(ctx, SMask, "S", PDF_NAME, (pdf_obj **)&S);
169
3.06k
        if (code <= 0) {
170
77
            subtype = TRANSPARENCY_MASK_Luminosity;
171
77
            pdfi_set_warning(ctx, 0, NULL, W_PDF_SMASK_MISSING_S, "pdfi_trans_set_mask", "");
172
77
        }
173
2.98k
        else if (pdfi_name_is(S, "Luminosity")) {
174
2.45k
            subtype = TRANSPARENCY_MASK_Luminosity;
175
2.45k
        } else if (pdfi_name_is(S, "Alpha")) {
176
529
            subtype = TRANSPARENCY_MASK_Alpha;
177
529
        } else {
178
6
            subtype = TRANSPARENCY_MASK_Luminosity;
179
6
            pdfi_set_warning(ctx, 0, NULL, W_PDF_SMASK_UNKNOWN_S, "pdfi_trans_set_mask", "");
180
6
        }
181
182
        /* TR is transfer function (Optional) */
183
3.06k
        code = pdfi_dict_knownget(ctx, SMask, "TR", (pdf_obj **)&TR);
184
3.06k
        if (code > 0) {
185
395
            switch (pdfi_type_of(TR)) {
186
6
                case PDF_DICT:
187
395
                case PDF_STREAM:
188
395
                    code = pdfi_build_function(ctx, &gsfunc, NULL, 1, TR, NULL);
189
395
                    if (code < 0)
190
52
                        goto exit;
191
343
                    if (gsfunc->params.m != 1 || gsfunc->params.n != 1) {
192
0
                        pdfi_free_function(ctx, gsfunc);
193
0
                        gsfunc = NULL;
194
0
                        pdfi_set_warning(ctx, 0, NULL, W_PDF_SMASK_INVALID_TR, "pdfi_trans_set_mask", "");
195
0
                    }
196
343
                    break;
197
0
                case PDF_NAME:
198
0
                    if (!pdfi_name_is((pdf_name *)TR, "Identity")) {
199
0
                        pdfi_set_warning(ctx, 0, NULL, W_PDF_SMASK_UNKNOWN_TR, "pdfi_trans_set_mask", "");
200
0
                    }
201
0
                    break;
202
0
                default:
203
0
                    pdfi_set_warning(ctx, 0, NULL, W_PDF_SMASK_UNKNOWN_TR_TYPE, "pdfi_trans_set_mask", "");
204
395
            }
205
395
        }
206
207
        /* BC is Background Color array (Optional) */
208
3.01k
        if (subtype == TRANSPARENCY_MASK_Luminosity)
209
2.53k
        {
210
2.53k
            code = pdfi_dict_knownget_type(ctx, SMask, "BC", PDF_ARRAY, (pdf_obj **)&BC);
211
2.53k
            if (code < 0)
212
49
                goto exit;
213
2.53k
        }
214
215
2.96k
        code = pdfi_dict_knownget_type(ctx, G_stream_dict, "BBox", PDF_ARRAY, (pdf_obj **)&BBox);
216
2.96k
        if (code < 0)
217
13
            goto exit;
218
2.94k
        code = pdfi_array_to_gs_rect(ctx, BBox, &bbox);
219
2.94k
        if (code < 0)
220
15
            goto exit;
221
222
2.93k
        gs_trans_mask_params_init(&params, subtype);
223
2.93k
        params.replacing = true;
224
2.93k
        if (gsfunc) {
225
343
            params.TransferFunction = pdfi_tf_using_function;
226
343
            params.TransferFunction_data = gsfunc;
227
343
        }
228
229
        /* Need to set just the ctm (GroupMat) from the saved GroupGState, to
230
           have gs_begin_transparency_mask work correctly.  Or at least that's
231
           what the PS code comments claim (see pdf_draw.ps/.execmaskgroup)
232
        */
233
2.93k
        gs_currentmatrix(ctx->pgs, &save_matrix);
234
2.93k
        gs_currentmatrix(igs->GroupGState, &GroupMat);
235
2.93k
        gs_setmatrix(ctx->pgs, &GroupMat);
236
237
2.93k
        code = pdfi_dict_knownget_type(ctx, G_stream_dict, "Matrix", PDF_ARRAY, (pdf_obj **)&Matrix);
238
2.93k
        if (code < 0)
239
0
            goto exit;
240
2.93k
        code = pdfi_array_to_gs_matrix(ctx, Matrix, &group_Matrix);
241
2.93k
        if (code < 0)
242
6
            goto exit;
243
244
        /* Transform the BBox by the Matrix */
245
2.92k
        pdfi_bbox_transform(ctx, &bbox, &group_Matrix);
246
247
2.92k
        if (gs_clip_bounds_in_user_space(ctx->pgs, &clip_bbox) >= 0)
248
2.84k
        {
249
2.84k
            rect_intersect(bbox, clip_bbox);
250
2.84k
            if (bbox.p.x >= bbox.q.x || bbox.p.y >= bbox.q.y)
251
542
            {
252
                /* If the bbox is illegal, we still need to set up an empty mask.
253
                 * We can't just skip forwards as everything will now be unmasked!
254
                 * We can skip doing the actual work though. */
255
542
                empty = 1;
256
542
            }
257
2.84k
        }
258
259
        /* CS is in the dict "Group" inside the dict "G" */
260
        /* TODO: Not sure if this is a required thing or just one possibility */
261
2.92k
        code = pdfi_dict_knownget_type(ctx, G_stream_dict, "Group", PDF_DICT, (pdf_obj **)&Group);
262
2.92k
        if (code < 0)
263
1.17k
            goto exit;
264
1.74k
        if (code > 0) {
265
            /* TODO: Stuff with colorspace, see .execmaskgroup */
266
1.62k
            code = pdfi_dict_knownget(ctx, Group, "CS", &CS);
267
1.62k
            if (code < 0) {
268
19
                code = pdfi_dict_knownget(ctx, Group, "ColorSpace", &CS);
269
19
                if (code < 0) {
270
0
                    pdfi_set_error(ctx, 0, NULL, E_PDF_GROUP_NO_CS, "pdfi_trans_set_mask", (char *)"*** Defaulting to currrent colour space");
271
0
                    goto exit;
272
0
                }
273
19
                pdfi_set_warning(ctx, 0, NULL, W_PDF_GROUP_HAS_COLORSPACE, "pdfi_trans_set_mask", NULL);
274
19
            }
275
1.62k
            if (code > 0) {
276
1.55k
                code = pdfi_create_colorspace(ctx, CS, (pdf_dict *)ctx->main_stream,
277
1.55k
                                              ctx->page.CurrentPageDict, &pcs, false);
278
1.55k
                params.ColorSpace = pcs;
279
1.55k
                if (code < 0)
280
188
                    goto exit;
281
1.55k
            }
282
65
            else
283
65
                   params.ColorSpace = NULL;
284
1.62k
        } else {
285
            /* GS and Adobe will ignore the whole mask in this case, so we do the same.
286
            */
287
125
            pdfi_set_error(ctx, 0, NULL, E_PDF_INVALID_TRANS_XOBJECT, "pdfi_trans_set_mask", (char *)"*** Error: Ignoring a transparency group XObject without /Group attribute");
288
125
            goto exit;
289
125
        }
290
291
        /* If there's a BC, put it in the params */
292
1.43k
        if (BC) {
293
565
            if (params.ColorSpace == NULL) {
294
19
                if ((code = pdfi_set_error_stop(ctx, gs_note_error(gs_error_undefined), NULL, E_PDF_GROUP_BAD_BC_NO_CS, "pdfi_trans_set_mask", NULL)) < 0)
295
0
                    goto exit;
296
546
            } else {
297
546
                int i, components = pdfi_array_size(BC);
298
546
                double num;
299
546
                int cspace_cmps;
300
301
546
                if (components > GS_CLIENT_COLOR_MAX_COMPONENTS) {
302
0
                    if ((code = pdfi_set_error_stop(ctx, gs_note_error(gs_error_limitcheck), NULL, E_PDF_GROUP_BAD_BC_TOO_BIG, "pdfi_trans_set_mask", NULL)) < 0)
303
0
                        goto exit;
304
546
                } else {
305
546
                    if ((cspace_cmps = gs_color_space_num_components(params.ColorSpace)) < 0) {
306
0
                        if ((code = pdfi_set_error_stop(ctx, gs_note_error(gs_error_undefinedresult), NULL, E_PDF_GROUP_BAD_CS, "pdfi_trans_set_mask", NULL)) < 0)
307
0
                            goto exit;
308
0
                    }
309
546
                    else {
310
546
                        if (gs_color_space_num_components(params.ColorSpace) != components) {
311
0
                            pdfi_set_warning(ctx, 0, NULL, W_PDF_GROUP_BAD_BC, "pdfi_trans_set_mask", NULL);
312
0
                            components = min(components, gs_color_space_num_components(params.ColorSpace));
313
0
                        }
314
315
2.36k
                        for (i=0; i < components; i++) {
316
1.81k
                            code = pdfi_array_get_number(ctx, BC, i, &num);
317
1.81k
                            if (code < 0)
318
0
                                break;
319
1.81k
                            params.Background[i] = (float)num;
320
1.81k
                        }
321
546
                        params.Background_components = components;
322
323
                        /* TODO: Not sure how to handle this...  recheck PS code (pdf_draw.ps/gssmask) */
324
                        /* This should be "currentgray" for the color that we put in params.ColorSpace,
325
                         * It looks super-convoluted to actually get this value.  Really?
326
                         * (see zcurrentgray())
327
                         * For now, use simple definition from PLRM2 and assume it is RGB or CMYK
328
                         */
329
546
                        pdfi_set_GrayBackground(&params);
330
546
                    }
331
546
                }
332
546
            }
333
565
        }
334
335
        /* When we call gs_begin_transparency_mask, the pdf14 compisitor will perform
336
         * a horrid pass through the graphics state, replacing "default" colorspaces
337
         * with "ps" ones. This is required, apparently, to give us proper rendering
338
         * of SMasks. Bug 705993 shows a case where the current colorspace differs
339
         * from the colorspace that will be used once the igs->GroupGState is swapped
340
         * in. Simply proceeding to call gs_begin_transparency_mask here, and then
341
         * setting the igs->GroupGState, leaves us with a colorspace where the
342
         * "default" -> "ps" change has not taken place, and we get incorrect rendering.
343
         *
344
         * As the igs->GroupGState can only be applied AFTER the
345
         * gs_begin_transparancy_mask call (that is, I couldn't make it work applying
346
         * it beforehand!), this means we need to manually swap in the colorspaces
347
         * and colors, and be careful to restore them afterwards.
348
         *
349
         * NOTE: Attempts to gsave/grestore around the gs_begin_transparency_mask/
350
         * gs_end_transparency_mask calls fail, showing diffs. My suspicion is that
351
         * this actually disables the softmask that we've just rendered!
352
         */
353
1.43k
        if (code >= 0) {
354
            /* Override the colorspace if specified */
355
1.43k
            saved_gs = gs_gstate_copy(ctx->pgs, ctx->memory);
356
1.43k
            if (saved_gs == NULL)
357
0
                code = gs_note_error(gs_error_VMerror);
358
1.43k
            if (code >= 0)
359
1.43k
                code = pdfi_gs_setcolorspace(ctx, igs->GroupGState->color[0].color_space);
360
1.43k
            if (code >= 0)
361
1.43k
                code = gs_setcolor(ctx->pgs, igs->GroupGState->color[0].ccolor);
362
1.43k
            gs_swapcolors_quick(ctx->pgs);
363
1.43k
            if (code >= 0)
364
1.43k
                code = pdfi_gs_setcolorspace(ctx, igs->GroupGState->color[1].color_space);
365
1.43k
            if (code >= 0)
366
1.43k
                code = gs_setcolor(ctx->pgs, igs->GroupGState->color[1].ccolor);
367
1.43k
            gs_swapcolors_quick(ctx->pgs);
368
1.43k
        }
369
370
1.43k
        if (code >= 0)
371
1.43k
            code = gs_begin_transparency_mask(ctx->pgs, &params, &bbox, false);
372
373
1.43k
        if (code >= 0) {
374
1.43k
            if (!empty)
375
1.35k
                code = pdfi_form_execgroup(ctx, ctx->page.CurrentPageDict, G_stream,
376
1.35k
                                           igs->GroupGState, NULL, NULL, &group_Matrix);
377
1.43k
            code1 = gs_end_transparency_mask(ctx->pgs, colorindex);
378
1.43k
            if (code == 0)
379
1.43k
                code = code1;
380
1.43k
        }
381
382
1.43k
        if (saved_gs) {
383
1.43k
            code1 = pdfi_gs_setcolorspace(ctx, saved_gs->color[0].color_space);
384
1.43k
            if (code >= 0) code = code1;
385
1.43k
            code1 = gs_setcolor(ctx->pgs, saved_gs->color[0].ccolor);
386
1.43k
            if (code >= 0) code = code1;
387
1.43k
            gs_swapcolors_quick(ctx->pgs);
388
1.43k
            code1 = pdfi_gs_setcolorspace(ctx, saved_gs->color[1].color_space);
389
1.43k
            if (code >= 0) code = code1;
390
1.43k
            code1 = gs_setcolor(ctx->pgs, saved_gs->color[1].ccolor);
391
1.43k
            if (code >= 0) code = code1;
392
1.43k
            gs_swapcolors_quick(ctx->pgs);
393
1.43k
        }
394
395
        /* Put back the matrix (we couldn't just rely on gsave/grestore for whatever reason,
396
         * according to PS code anyway...
397
         */
398
1.43k
        gs_setmatrix(ctx->pgs, &save_matrix);
399
400
        /* Set Processed flag */
401
1.43k
        if (code == 0 && ProcessedKnown)
402
1.43k
        {
403
1.43k
            code = pdfi_dict_put_bool(ctx, SMask, "Processed", true);
404
1.43k
            if (code < 0)
405
0
                goto exit;
406
1.43k
        }
407
1.43k
    } else {
408
        /* take action on a non-/Mask entry. What does this mean ? What do we need to do */
409
31
        pdfi_set_warning(ctx, 0, NULL, W_PDF_SMASK_UNKNOWN_TYPE, "pdfi_trans_set_mask", "");
410
31
    }
411
412
7.66k
 exit:
413
7.66k
    gs_gstate_free(saved_gs);
414
7.66k
    gs_setoverrideicc(ctx->pgs, save_OverrideICC);
415
7.66k
    if (gsfunc)
416
343
        pdfi_free_function(ctx, gsfunc);
417
7.66k
    if (pcs)
418
1.37k
        rc_decrement_cs(pcs, "pdfi_trans_set_mask");
419
7.66k
    pdfi_countdown(n);
420
7.66k
    pdfi_countdown(S);
421
7.66k
    pdfi_countdown(Group);
422
7.66k
    pdfi_countdown(G_stream);
423
7.66k
    pdfi_countdown(a);
424
7.66k
    pdfi_countdown(BC);
425
7.66k
    pdfi_countdown(TR);
426
7.66k
    pdfi_countdown(BBox);
427
7.66k
    pdfi_countdown(Matrix);
428
7.66k
    pdfi_countdown(CS);
429
#if DEBUG_TRANSPARENCY
430
    dbgmprintf(ctx->memory, "pdfi_trans_set_mask (.execmaskgroup) END\n");
431
#endif
432
7.66k
    return code;
433
6.72k
}
434
435
/* Wrapper around gs call to setup the transparency params correctly */
436
static int pdfi_gs_begin_transparency_group(gs_gstate * pgs,
437
                                       gs_transparency_group_params_t *params,
438
                                       const gs_rect *pbbox, pdf14_compositor_operations group_type)
439
50.2k
{
440
50.2k
    if (gs_getalphaisshape(pgs)) {
441
1.40k
        params->group_shape = gs_getfillconstantalpha(pgs);
442
1.40k
        params->group_opacity = 1.0;
443
48.8k
    } else {
444
48.8k
        params->group_opacity = gs_getfillconstantalpha(pgs);
445
48.8k
        params->group_shape = 1.0;
446
48.8k
    }
447
448
50.2k
    return gs_begin_transparency_group(pgs, params, pbbox, group_type);
449
50.2k
}
450
451
static int pdfi_transparency_group_common(pdf_context *ctx, pdf_dict *page_dict,
452
                                          pdf_dict *group_dict,
453
                                          gs_rect *bbox, pdf14_compositor_operations group_type)
454
10.5k
{
455
10.5k
    gs_transparency_group_params_t params;
456
10.5k
    pdf_obj *CS = NULL;
457
10.5k
    bool b;
458
10.5k
    int code;
459
460
10.5k
    gs_trans_group_params_init(&params, 1.0);
461
    /*    gs_setopacityalpha(ctx->pgs, ctx->pgs->fillconstantalpha); */
462
463
    /* It seems the flag for Isolated is /I */
464
10.5k
    code = pdfi_dict_get_bool(ctx, group_dict, "I", &b);
465
10.5k
    if (code < 0 && code != gs_error_undefined)
466
0
        return_error(code);
467
10.5k
    if (code == gs_error_undefined)
468
5.65k
        params.Isolated = false;
469
4.85k
    else
470
4.85k
        params.Isolated = b;
471
472
    /* It seems the flag for Knockout is /K */
473
10.5k
    code = pdfi_dict_get_bool(ctx, group_dict, "K", &b);
474
10.5k
    if (code < 0 && code != gs_error_undefined)
475
0
        goto exit;
476
10.5k
    if (code == gs_error_undefined)
477
5.66k
        params.Knockout = false;
478
4.85k
    else
479
4.85k
        params.Knockout = b;
480
481
10.5k
    params.image_with_SMask = false;
482
10.5k
    params.ColorSpace = NULL;
483
484
10.5k
    code = pdfi_dict_knownget(ctx, group_dict, "CS", &CS);
485
10.5k
    if (code == 0) {
486
        /* Didn't find a /CS key, try again using /ColorSpace */
487
1.94k
        code = pdfi_dict_knownget(ctx, group_dict, "ColorSpace", &CS);
488
1.94k
    }
489
10.5k
    if (code > 0 && pdfi_type_of(CS) != PDF_NULL) {
490
8.09k
        code = pdfi_setcolorspace(ctx, CS, group_dict, page_dict);
491
8.09k
        if (code < 0)
492
194
            goto exit;
493
7.90k
        params.ColorSpace = gs_currentcolorspace(ctx->pgs);
494
7.90k
    } else {
495
2.41k
        params.ColorSpace = NULL;
496
2.41k
    }
497
498
10.5k
 exit:
499
10.5k
    pdfi_countdown(CS);
500
10.5k
    if (code < 0)
501
348
        return_error(code);
502
503
10.1k
    return pdfi_gs_begin_transparency_group(ctx->pgs, &params, (const gs_rect *)bbox, group_type);
504
10.5k
}
505
506
static bool pdfi_outputprofile_matches_oiprofile(pdf_context *ctx)
507
0
{
508
0
    cmm_dev_profile_t *profile_struct;
509
0
    int code;
510
0
    int k;
511
512
0
    code = dev_proc(ctx->pgs->device, get_profile)(ctx->pgs->device,  &profile_struct);
513
0
    if (code < 0)
514
0
        return true;  /* Assume they match by default and in error condition */
515
516
0
    if (profile_struct->oi_profile == NULL)
517
0
        return true; /* no OI profile so no special case to worry about */
518
0
    else {
519
        /* Check the device profile(s). If any of them do not match, then
520
           we assume there is not a match and it may be necessary to
521
           use the pdf14 device to prerender to the OI profile */
522
0
        for (k = 0; k < NUM_DEVICE_PROFILES; k++) {
523
0
            if (profile_struct->device_profile[k] != NULL) {
524
0
                if (!gsicc_profiles_equal(profile_struct->oi_profile, profile_struct->device_profile[k]))
525
0
                    return false;
526
0
            }
527
0
        }
528
0
        return true;
529
0
    }
530
0
}
531
532
/* Begin a simple group
533
 * pathbbox -- bbox to use, but can be NULL
534
 */
535
int pdfi_trans_begin_simple_group(pdf_context *ctx, gs_rect *pathbbox,
536
                                  bool stroked_bbox, bool isolated, bool knockout)
537
14.5k
{
538
14.5k
    gs_transparency_group_params_t params;
539
14.5k
    gs_rect bbox;
540
14.5k
    int code;
541
542
14.5k
    gs_trans_group_params_init(&params, 1.0);
543
14.5k
    params.Isolated = isolated;
544
14.5k
    params.Knockout = knockout;
545
546
14.5k
    if (!pathbbox) {
547
12.5k
        code = pdfi_get_current_bbox(ctx, &bbox, stroked_bbox);
548
12.5k
        if (code < 0)
549
882
            return code;
550
11.6k
        pathbbox = &bbox;
551
11.6k
    }
552
553
13.7k
    code = pdfi_gs_begin_transparency_group(ctx->pgs, &params, pathbbox, PDF14_BEGIN_TRANS_GROUP);
554
13.7k
    if (code >=  0)
555
13.7k
        ctx->current_stream_save.group_depth++;
556
13.7k
    return code;
557
14.5k
}
558
559
int pdfi_trans_begin_page_group(pdf_context *ctx, pdf_dict *page_dict, pdf_dict *group_dict)
560
4.82k
{
561
4.82k
    gs_rect bbox;
562
4.82k
    int code;
563
564
4.82k
    if (group_dict == NULL)
565
0
        return_error(gs_error_undefined);
566
567
4.82k
    code = pdfi_gsave(ctx);
568
4.82k
    bbox.p.x = ctx->page.Size[0];
569
4.82k
    bbox.p.y = ctx->page.Size[1];
570
4.82k
    bbox.q.x = ctx->page.Size[2];
571
4.82k
    bbox.q.y = ctx->page.Size[3];
572
573
4.82k
    code = pdfi_transparency_group_common(ctx, page_dict, group_dict, &bbox, PDF14_BEGIN_TRANS_PAGE_GROUP);
574
4.82k
    if (code < 0)
575
128
        pdfi_grestore(ctx);
576
4.69k
    else
577
4.69k
        ctx->current_stream_save.group_depth++;
578
579
4.82k
    return code;
580
4.82k
}
581
582
int pdfi_trans_begin_form_group(pdf_context *ctx, pdf_dict *page_dict, pdf_dict *form_dict)
583
5.99k
{
584
5.99k
    pdf_obj *group_obj = NULL;
585
5.99k
    gs_rect bbox;
586
5.99k
    pdf_array *BBox = NULL;
587
5.99k
    int code;
588
5.99k
    pdf_dict *group_dict = NULL;
589
590
    /* TODO: Maybe sometimes this is actually a stream?
591
     * Otherwise should just fetch it as a dict.
592
     * Anyway this will work for either dict or stream
593
     */
594
5.99k
    code = pdfi_dict_get(ctx, form_dict, "Group", &group_obj);
595
5.99k
    if (code < 0)
596
217
        return_error(code);
597
598
5.77k
    code = pdfi_dict_from_obj(ctx, (pdf_obj *)group_obj, &group_dict);
599
5.77k
    if (code < 0)
600
86
        goto exit;
601
602
5.69k
    code = pdfi_gsave(ctx);
603
5.69k
    code = pdfi_dict_knownget_type(ctx, form_dict, "BBox", PDF_ARRAY, (pdf_obj **)&BBox);
604
5.69k
    if (code < 0)
605
0
        goto exit;
606
5.69k
    if (code > 0) {
607
5.68k
        code = pdfi_array_to_gs_rect(ctx, BBox, &bbox);
608
5.68k
        if (code < 0)
609
0
            goto exit;
610
5.68k
    } else {
611
3
        bbox.p.x = 0;
612
3
        bbox.p.y = 0;
613
3
        bbox.q.x = 0;
614
3
        bbox.q.y = 0;
615
3
    }
616
617
5.69k
    code = pdfi_transparency_group_common(ctx, page_dict, group_dict, &bbox, PDF14_BEGIN_TRANS_GROUP);
618
5.69k
    if (code < 0)
619
220
        pdfi_grestore(ctx);
620
5.47k
    else
621
5.47k
        ctx->current_stream_save.group_depth++;
622
623
5.77k
 exit:
624
5.77k
    pdfi_countdown(BBox);
625
5.77k
    pdfi_countdown(group_obj);
626
5.77k
    return code;
627
5.69k
}
628
629
630
int pdfi_trans_end_group(pdf_context *ctx)
631
10.1k
{
632
10.1k
    int code;
633
634
10.1k
    code = gs_end_transparency_group(ctx->pgs);
635
10.1k
    if (code < 0)
636
0
        pdfi_grestore(ctx);
637
10.1k
    else
638
10.1k
        code = pdfi_grestore(ctx);
639
640
10.1k
    ctx->current_stream_save.group_depth--;
641
642
10.1k
    return code;
643
10.1k
}
644
645
/* Ends group with no grestore */
646
int pdfi_trans_end_simple_group(pdf_context *ctx)
647
13.6k
{
648
13.6k
    int code;
649
650
13.6k
    code = gs_end_transparency_group(ctx->pgs);
651
13.6k
    ctx->current_stream_save.group_depth--;
652
653
13.6k
    return code;
654
13.6k
}
655
656
657
int pdfi_trans_begin_isolated_group(pdf_context *ctx, bool image_with_SMask, gs_color_space *pcs)
658
26.4k
{
659
26.4k
    gs_transparency_group_params_t params;
660
26.4k
    gs_rect bbox;
661
26.4k
    gs_rect clip_box;
662
663
26.4k
    gs_trans_group_params_init(&params, 1.0);
664
665
26.4k
    params.ColorSpace = pcs;
666
26.4k
    params.Isolated = true;
667
26.4k
    params.Knockout = false;
668
26.4k
    params.image_with_SMask = image_with_SMask;
669
26.4k
    bbox.p.x = 0;
670
26.4k
    bbox.p.y = 0;
671
26.4k
    bbox.q.x = 1;
672
26.4k
    bbox.q.y = 1;
673
26.4k
    if (gs_clip_bounds_in_user_space(ctx->pgs, &clip_box) >= 0)
674
26.4k
        rect_intersect(bbox, clip_box);
675
676
26.4k
    return pdfi_gs_begin_transparency_group(ctx->pgs, &params, &bbox, PDF14_BEGIN_TRANS_GROUP);
677
26.4k
}
678
679
int pdfi_trans_end_isolated_group(pdf_context *ctx)
680
26.4k
{
681
26.4k
    return gs_end_transparency_group(ctx->pgs);
682
26.4k
}
683
684
685
/* This notifies the compositor that we're done with an smask.  Seems hacky.
686
 * See pdf_draw.ps/doimagesmask.
687
 */
688
int pdfi_trans_end_smask_notify(pdf_context *ctx)
689
31.7k
{
690
31.7k
    gs_transparency_mask_params_t params;
691
31.7k
    gs_rect bbox;
692
693
31.7k
    gs_trans_mask_params_init(&params, TRANSPARENCY_MASK_None);
694
31.7k
    params.replacing = true;
695
696
31.7k
    bbox.p.x = 0;
697
31.7k
    bbox.p.y = 0;
698
31.7k
    bbox.q.x = 0;
699
31.7k
    bbox.q.y = 0;
700
701
31.7k
    return gs_begin_transparency_mask(ctx->pgs, &params, &bbox, false);
702
31.7k
}
703
704
/* Setup whether or not we need to support overprint (for device)
705
 * Check for:
706
 *   1) how many components the device has (CMYK or other)
707
 *   2) whether it is a device that has transparency support
708
 *   3) Overprint mode (enable, disable, simulate)
709
 * Based on pdf_main.ps/pdfshowpage_finish
710
 * Test file (run with -dOverprint=/simulate)
711
 *    tests_private/pdf/uploads/op_trans_spot_testing.pdf
712
 */
713
void pdfi_trans_set_needs_OP(pdf_context *ctx)
714
109k
{
715
109k
    bool is_cmyk;
716
109k
    bool device_transparency = false;
717
718
    /* PS code checks for >= 4 components... */
719
109k
    is_cmyk = ctx->pgs->device->color_info.num_components >= 4 && ctx->pgs->device->color_info.polarity == GX_CINFO_POLARITY_SUBTRACTIVE;
720
721
109k
    device_transparency = pdfi_device_check_param_bool(ctx->pgs->device, "HaveTransparency");
722
723
109k
    ctx->page.needs_OP = false;
724
109k
    ctx->page.simulate_op = false;
725
109k
    switch(ctx->pgs->device->icc_struct->overprint_control) {
726
0
    case gs_overprint_control_disable:
727
        /* Use defaults */
728
0
        break;
729
0
    case gs_overprint_control_simulate:
730
0
        if (!device_transparency && ctx->page.has_OP) {
731
0
            if (is_cmyk) {
732
                /* If the page has spots and the device is not spot capable OR
733
                   if the output intent profile is to be used, but we have
734
                   a device output profile that is different, then we will be
735
                   doing simulation with the pdf14 device buffer */
736
0
                if ((ctx->page.num_spots > 0  && !ctx->device_state.spot_capable) ||
737
0
                    !pdfi_outputprofile_matches_oiprofile(ctx)) {
738
0
                    ctx->page.needs_OP = true;
739
0
                    ctx->page.simulate_op = true;
740
0
                }
741
0
            } else {
742
0
                ctx->page.needs_OP = true;
743
0
                ctx->page.simulate_op = true;
744
0
            }
745
0
        }
746
0
        break;
747
109k
    case gs_overprint_control_enable:
748
109k
    default:
749
109k
        if (!is_cmyk || device_transparency)
750
96.8k
            ctx->page.needs_OP = false;
751
12.6k
        else
752
12.6k
            ctx->page.needs_OP = true;
753
109k
        break;
754
109k
    }
755
756
109k
    if(ctx->args.pdfdebug)
757
109k
        dbgmprintf2(ctx->memory, "Page %s Overprint, Simulate is %s\n",
758
109k
                    ctx->page.needs_OP ? "NEEDS" : "does NOT NEED",
759
109k
                    ctx->page.simulate_op ? "TRUE" : "FALSE");
760
109k
}
761
762
/* Figures out if current colorspace is okay for Overprint (see pdf_ops.ps/okOPcs and setupOPtrans) */
763
bool pdfi_trans_okOPcs(pdf_context *ctx)
764
148k
{
765
148k
    gs_color_space_index csi;
766
767
148k
    csi = pdfi_currentcolorspace(ctx, 0);
768
769
148k
    switch (csi) {
770
23.7k
    case gs_color_space_index_DeviceGray:
771
25.2k
    case gs_color_space_index_DeviceCMYK:
772
25.2k
    case gs_color_space_index_DeviceN:
773
26.2k
    case gs_color_space_index_Separation:
774
        /* These are colorspaces that don't require special handling for overprint.
775
         * (pdf1.7 pg 259,578 may apply)
776
         * According to mvrhel, DeviceGray should also be included (see comment in gx_set_overprint_ICC()).
777
         * Sample: 030_Gray_K_black_OP_x1a.pdf (??)
778
         */
779
#if DEBUG_TRANSPARENCY
780
        dbgmprintf1(ctx->memory, "Colorspace is %d, OKAY for OVERPRINT\n", csi);
781
#endif
782
26.2k
        return true;
783
121k
    default:
784
#if DEBUG_TRANSPARENCY
785
        dbgmprintf1(ctx->memory, "Colorspace is %d, NOT OKAY for OVERPRINT\n", csi);
786
#endif
787
121k
        return false;
788
148k
    }
789
790
0
    return false;
791
148k
}
792
793
int pdfi_trans_setup(pdf_context *ctx, pdfi_trans_state_t *state, gs_rect *bbox,
794
                           pdfi_transparency_caller_t caller)
795
5.45M
{
796
5.45M
    pdfi_int_gstate *igs = (pdfi_int_gstate *)ctx->pgs->client_data;
797
5.45M
    int code;
798
5.45M
    bool stroked_bbox;
799
5.45M
    bool current_overprint;
800
5.45M
    bool okOPcs = false;
801
5.45M
    bool ChangeBM = false;
802
5.45M
    gs_blend_mode_t  mode = gs_currentblendmode(ctx->pgs);  /* quite warning */
803
5.45M
    bool need_group = false;
804
805
5.45M
    memset(state, 0, sizeof(*state));
806
807
5.45M
    if (!ctx->page.has_transparency)
808
4.70M
        return 0;
809
810
750k
    if (ctx->page.needs_OP) {
811
144k
        okOPcs = pdfi_trans_okOPcs(ctx);
812
144k
        if (okOPcs) {
813
26.2k
            if (caller == TRANSPARENCY_Caller_Stroke)
814
15.1k
                current_overprint = gs_currentstrokeoverprint(ctx->pgs);
815
11.1k
            else {
816
11.1k
                current_overprint = gs_currentfilloverprint(ctx->pgs);
817
11.1k
                if (caller == TRANSPARENCY_Caller_FillStroke)
818
274
                    current_overprint |= gs_currentstrokeoverprint(ctx->pgs);
819
11.1k
            }
820
26.2k
            ChangeBM = current_overprint;
821
26.2k
            mode = gs_currentblendmode(ctx->pgs);
822
26.2k
            if (mode != BLEND_MODE_Normal && mode != BLEND_MODE_Compatible)
823
608
                need_group = ChangeBM;
824
25.6k
            else
825
25.6k
                need_group = false;
826
118k
        } else {
827
118k
            need_group = false;
828
118k
        }
829
144k
        need_group = need_group || (igs->SMask != NULL);
830
605k
    } else {
831
605k
        if (caller == TRANSPARENCY_Caller_Image || igs->SMask == NULL)
832
599k
            need_group = false;
833
5.74k
        else
834
5.74k
            need_group = true;
835
605k
    }
836
837
750k
    code = pdfi_trans_set_params(ctx);
838
750k
    if (code != 0)
839
1.37k
        return 0;
840
841
749k
    if (!need_group && !ChangeBM)
842
740k
        return 0;
843
844
    /* TODO: error handling... */
845
8.57k
    if (need_group) {
846
4.94k
        bool isolated = false;
847
4.94k
        mode = gs_currentblendmode(ctx->pgs);
848
849
4.94k
        stroked_bbox = (caller == TRANSPARENCY_Caller_Stroke || caller == TRANSPARENCY_Caller_FillStroke);
850
851
        /* When changing to compatible overprint bm, the group pushed must be non-isolated. The exception
852
           is if we have a softmask AND the blend mode is not normal and not compatible.
853
           See /setupOPtrans in pdf_ops.ps  */
854
4.94k
        if (igs->SMask != NULL && mode != BLEND_MODE_Normal && mode != BLEND_MODE_Compatible)
855
1.90k
            isolated = true;
856
4.94k
        code = pdfi_trans_begin_simple_group(ctx, bbox, stroked_bbox, isolated, false);
857
858
        /* Group was not pushed if error */
859
4.94k
        if (code >= 0)
860
4.06k
            state->GroupPushed = true;
861
862
4.94k
        state->saveStrokeAlpha = gs_getstrokeconstantalpha(ctx->pgs);
863
4.94k
        state->saveFillAlpha = gs_getfillconstantalpha(ctx->pgs);
864
4.94k
        code = gs_setfillconstantalpha(ctx->pgs, 1.0);
865
4.94k
        code = gs_setstrokeconstantalpha(ctx->pgs, 1.0);
866
4.94k
    }
867
868
    /* If we are in a fill stroke situation, do not change the blend mode.
869
       We can have situations where the fill and the stroke have different
870
       blending needs (one may need compatible overprint and the other may
871
       need the normal mode) This is all handled in the fill stroke logic */
872
8.57k
    if (ChangeBM && caller != TRANSPARENCY_Caller_FillStroke) {
873
3.76k
        state->saveBM = mode;
874
3.76k
        state->ChangeBM = true;
875
3.76k
        code = gs_setblendmode(ctx->pgs, BLEND_MODE_CompatibleOverprint);
876
3.76k
    }
877
8.57k
    return code;
878
749k
}
879
880
int pdfi_trans_required(pdf_context *ctx)
881
25.0M
{
882
25.0M
    gs_blend_mode_t mode;
883
884
25.0M
    if (!ctx->page.has_transparency)
885
19.4M
        return 0;
886
887
5.61M
    mode = gs_currentblendmode(ctx->pgs);
888
5.61M
    if ((mode == BLEND_MODE_Normal || mode == BLEND_MODE_Compatible) &&
889
5.60M
        ctx->pgs->fillconstantalpha == 1 &&
890
5.57M
        ctx->pgs->strokeconstantalpha == 1 &&
891
5.57M
        ((pdfi_int_gstate *)ctx->pgs->client_data)->SMask == NULL)
892
5.56M
        return 0;
893
894
43.3k
    return 1;
895
5.61M
}
896
897
int pdfi_trans_setup_text(pdf_context *ctx, pdfi_trans_state_t *state, bool is_show)
898
12.3M
{
899
12.3M
    int Trmode;
900
12.3M
    int code, code1;
901
12.3M
    gs_rect bbox;
902
903
12.3M
    if (!pdfi_trans_required(ctx))
904
12.3M
        return 0;
905
906
17.8k
    Trmode = gs_currenttextrenderingmode(ctx->pgs);
907
17.8k
    code = gs_gsave(ctx->pgs);
908
17.8k
    if (code < 0) goto exit;
909
910
17.8k
    if (is_show) {
911
17.8k
        code = gs_clippath(ctx->pgs);
912
17.8k
    } else {
913
0
        code = gs_strokepath(ctx->pgs);
914
0
    }
915
17.8k
    if (code >= 0)
916
17.8k
        code = gs_upathbbox(ctx->pgs, &bbox, false);
917
17.8k
    if (code < 0) {
918
        /* Just set bbox to [0,0,0,0] */
919
4
        bbox.p.x = bbox.p.y = bbox.q.x = bbox.q.y = 0.0;
920
4
        code = 0;
921
4
    }
922
17.8k
    code1 = gs_grestore(ctx->pgs);
923
17.8k
    if (code == 0) code = code1;
924
17.8k
    if (code < 0) goto exit;
925
926
17.8k
    switch (Trmode) {
927
17.7k
    case 0:
928
17.7k
        code = pdfi_trans_setup(ctx, state, &bbox, TRANSPARENCY_Caller_Fill);
929
17.7k
        break;
930
59
    default:
931
        /* TODO: All the others */
932
59
        code = pdfi_trans_setup(ctx, state, &bbox, TRANSPARENCY_Caller_Fill);
933
59
        break;
934
17.8k
    }
935
936
17.8k
 exit:
937
17.8k
    return code;
938
17.8k
}
939
940
int pdfi_trans_teardown_text(pdf_context *ctx, pdfi_trans_state_t *state)
941
12.3M
{
942
12.3M
    if (!pdfi_trans_required(ctx))
943
12.3M
         return 0;
944
945
17.8k
    return pdfi_trans_teardown(ctx, state);
946
12.3M
}
947
948
int pdfi_trans_teardown(pdf_context *ctx, pdfi_trans_state_t *state)
949
5.45M
{
950
5.45M
    int code = 0;
951
952
5.45M
    if (!ctx->page.has_transparency)
953
4.70M
        return 0;
954
955
750k
    if (state->GroupPushed) {
956
4.06k
        code = pdfi_trans_end_simple_group(ctx);
957
4.06k
        code = gs_setstrokeconstantalpha(ctx->pgs, state->saveStrokeAlpha);
958
4.06k
        code = gs_setfillconstantalpha(ctx->pgs, state->saveFillAlpha);
959
4.06k
    }
960
961
750k
    if (gs_currentblendmode(ctx->pgs) == BLEND_MODE_CompatibleOverprint)
962
3.76k
        code = gs_setblendmode(ctx->pgs, state->saveBM);
963
964
750k
    return code;
965
5.45M
}
966
967
int pdfi_trans_set_params(pdf_context *ctx)
968
1.10M
{
969
1.10M
    int code = 0;
970
1.10M
    pdfi_int_gstate *igs = (pdfi_int_gstate *)ctx->pgs->client_data;
971
1.10M
    gs_transparency_channel_selector_t csel;
972
973
1.10M
    if (ctx->page.has_transparency) {
974
875k
        if (gs_getalphaisshape(ctx->pgs))
975
3.53k
            csel = TRANSPARENCY_CHANNEL_Shape;
976
871k
        else
977
871k
            csel = TRANSPARENCY_CHANNEL_Opacity;
978
875k
        if (igs->SMask) {
979
7.66k
            code = pdfi_trans_set_mask(ctx, igs, csel);
980
7.66k
        }
981
875k
    }
982
983
1.10M
    return code;
984
1.10M
}