Coverage Report

Created: 2025-11-16 07:40

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
110k
{
42
110k
    float in = in_val;
43
110k
    gs_function_t *const pfn = proc_data;
44
45
110k
    return gs_function_evaluate(pfn, &in, out);
46
110k
}
47
48
static void
49
pdfi_set_GrayBackground(gs_transparency_mask_params_t *params)
50
2.34k
{
51
2.34k
    float num;
52
2.34k
    int i;
53
54
8.33k
    for (i = 0; i < params->Background_components; i++)
55
5.99k
    {
56
5.99k
        if (params->Background[i] < 0)
57
0
            params->Background[i] = 0;
58
5.99k
        else if (params->Background[i] > 1)
59
0
            params->Background[i] = 1;
60
5.99k
    }
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
2.34k
    switch(params->Background_components) {
68
25
    case 3:
69
        /* RGB: currentgray = 0.3*R + 0.59*G + 0.11*B */
70
25
        params->GrayBackground = (0.3 * params->Background[0] +
71
25
                                  0.59 * params->Background[1] +
72
25
                                  0.11 * params->Background[2]);
73
25
        break;
74
1.20k
    case 4:
75
        /* CMYK: currentgray = 1.0 – min (1.0, .3*C + .59*M + .11*Y + K)
76
        */
77
1.20k
        num = 0.3*params->Background[0] + 0.59*params->Background[1] +
78
1.20k
            0.11*params->Background[2] + params->Background[3];
79
1.20k
        params->GrayBackground = 1 - num;
80
1.20k
        break;
81
1.11k
    case 1:
82
1.11k
        params->GrayBackground = params->Background[0];
83
1.11k
        break;
84
0
    default:
85
        /* No clue... */
86
0
        params->GrayBackground = 0;
87
2.34k
    }
88
2.34k
    if (params->GrayBackground < 0)
89
1.13k
        params->GrayBackground = 0;
90
1.20k
    else if (params->GrayBackground > 1)
91
0
        params->GrayBackground = 1;
92
2.34k
}
93
94
/* (see pdf_draw.ps/execmaskgroup) */
95
static int pdfi_trans_set_mask(pdf_context *ctx, pdfi_int_gstate *igs, int colorindex)
96
14.2k
{
97
14.2k
    int code = 0, code1 = 0;
98
14.2k
    pdf_dict *SMask = igs->SMask;
99
14.2k
    gs_color_space *pcs = NULL;
100
14.2k
    gs_rect bbox;
101
14.2k
    gs_transparency_mask_params_t params;
102
14.2k
    pdf_array *BBox = NULL;
103
14.2k
    pdf_array *Matrix = NULL;
104
14.2k
    pdf_array *a = NULL;
105
14.2k
    pdf_array *BC = NULL;
106
14.2k
    pdf_stream *G_stream = NULL;
107
14.2k
    pdf_dict *G_stream_dict = NULL;
108
14.2k
    pdf_dict *Group = NULL;
109
14.2k
    pdf_obj *TR = NULL;
110
14.2k
    gs_function_t *gsfunc = NULL;
111
14.2k
    pdf_name *n = NULL;
112
14.2k
    pdf_name *S = NULL;
113
14.2k
    pdf_obj *CS = NULL;
114
14.2k
    gs_matrix save_matrix, GroupMat, group_Matrix;
115
14.2k
    gs_transparency_mask_subtype_t subtype = TRANSPARENCY_MASK_Luminosity;
116
14.2k
    bool Processed, ProcessedKnown = 0;
117
14.2k
    bool save_OverrideICC = gs_currentoverrideicc(ctx->pgs);
118
14.2k
    gs_gstate *saved_gs = NULL;
119
14.2k
    gs_rect clip_bbox;
120
14.2k
    int empty = 0;
121
122
#if DEBUG_TRANSPARENCY
123
    dbgmprintf(ctx->memory, "pdfi_trans_set_mask (.execmaskgroup) BEGIN\n");
124
#endif
125
14.2k
    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
14.2k
    code = pdfi_dict_knownget_bool(ctx, SMask, "Processed", &Processed);
131
14.2k
    if (code > 0) {
132
7.96k
        if (Processed) {
133
#if DEBUG_TRANSPARENCY
134
          dbgmprintf(ctx->memory, "SMask already built, skipping\n");
135
#endif
136
1.96k
          code = 0;
137
1.96k
          goto exit;
138
1.96k
        }
139
6.00k
        ProcessedKnown = 1;
140
6.00k
    }
141
142
12.2k
    gs_setoverrideicc(ctx->pgs, true);
143
144
    /* If /Processed not in the dict, put it there */
145
12.2k
    if (code == 0) {
146
6.25k
        code = pdfi_dict_put_bool(ctx, SMask, "Processed", false);
147
6.25k
        if (code < 0)
148
0
            goto exit;
149
6.25k
        ProcessedKnown = 1;
150
6.25k
    }
151
152
    /* See pdf1.7 pg 553 (pain in the butt to find this!) */
153
12.2k
    code = pdfi_dict_knownget_type(ctx, SMask, "Type", PDF_NAME, (pdf_obj **)&n);
154
12.2k
    if (code == 0 || (code > 0 && pdfi_name_is(n, "Mask"))) {
155
        /* G is transparency group XObject (required) */
156
12.1k
        code = pdfi_dict_knownget_type(ctx, SMask, "G", PDF_STREAM, (pdf_obj **)&G_stream);
157
12.1k
        if (code <= 0) {
158
5.26k
            pdfi_trans_end_smask_notify(ctx);
159
5.26k
            code = pdfi_set_error_stop(ctx, code, NULL, E_PDF_SMASK_MISSING_G, "pdfi_trans_set_mask", "");
160
5.26k
            goto exit;
161
5.26k
        }
162
163
6.87k
        code = pdfi_dict_from_obj(ctx, (pdf_obj *)G_stream, &G_stream_dict);
164
6.87k
        if (code < 0)
165
0
            goto exit;
166
167
        /* S is a subtype name (required) */
168
6.87k
        code = pdfi_dict_knownget_type(ctx, SMask, "S", PDF_NAME, (pdf_obj **)&S);
169
6.87k
        if (code <= 0) {
170
261
            subtype = TRANSPARENCY_MASK_Luminosity;
171
261
            pdfi_set_warning(ctx, 0, NULL, W_PDF_SMASK_MISSING_S, "pdfi_trans_set_mask", "");
172
261
        }
173
6.61k
        else if (pdfi_name_is(S, "Luminosity")) {
174
6.04k
            subtype = TRANSPARENCY_MASK_Luminosity;
175
6.04k
        } else if (pdfi_name_is(S, "Alpha")) {
176
559
            subtype = TRANSPARENCY_MASK_Alpha;
177
559
        } else {
178
14
            subtype = TRANSPARENCY_MASK_Luminosity;
179
14
            pdfi_set_warning(ctx, 0, NULL, W_PDF_SMASK_UNKNOWN_S, "pdfi_trans_set_mask", "");
180
14
        }
181
182
        /* TR is transfer function (Optional) */
183
6.87k
        code = pdfi_dict_knownget(ctx, SMask, "TR", (pdf_obj **)&TR);
184
6.87k
        if (code > 0) {
185
484
            switch (pdfi_type_of(TR)) {
186
7
                case PDF_DICT:
187
484
                case PDF_STREAM:
188
484
                    code = pdfi_build_function(ctx, &gsfunc, NULL, 1, TR, NULL);
189
484
                    if (code < 0)
190
53
                        goto exit;
191
431
                    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
431
                    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
484
            }
205
484
        }
206
207
        /* BC is Background Color array (Optional) */
208
6.82k
        if (subtype == TRANSPARENCY_MASK_Luminosity)
209
6.31k
        {
210
6.31k
            code = pdfi_dict_knownget_type(ctx, SMask, "BC", PDF_ARRAY, (pdf_obj **)&BC);
211
6.31k
            if (code < 0)
212
121
                goto exit;
213
6.31k
        }
214
215
6.70k
        code = pdfi_dict_knownget_type(ctx, G_stream_dict, "BBox", PDF_ARRAY, (pdf_obj **)&BBox);
216
6.70k
        if (code < 0)
217
12
            goto exit;
218
6.68k
        code = pdfi_array_to_gs_rect(ctx, BBox, &bbox);
219
6.68k
        if (code < 0)
220
19
            goto exit;
221
222
6.66k
        gs_trans_mask_params_init(&params, subtype);
223
6.66k
        params.replacing = true;
224
6.66k
        if (gsfunc) {
225
431
            params.TransferFunction = pdfi_tf_using_function;
226
431
            params.TransferFunction_data = gsfunc;
227
431
        }
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
6.66k
        gs_currentmatrix(ctx->pgs, &save_matrix);
234
6.66k
        gs_currentmatrix(igs->GroupGState, &GroupMat);
235
6.66k
        gs_setmatrix(ctx->pgs, &GroupMat);
236
237
6.66k
        code = pdfi_dict_knownget_type(ctx, G_stream_dict, "Matrix", PDF_ARRAY, (pdf_obj **)&Matrix);
238
6.66k
        if (code < 0)
239
0
            goto exit;
240
6.66k
        code = pdfi_array_to_gs_matrix(ctx, Matrix, &group_Matrix);
241
6.66k
        if (code < 0)
242
10
            goto exit;
243
244
        /* Transform the BBox by the Matrix */
245
6.65k
        pdfi_bbox_transform(ctx, &bbox, &group_Matrix);
246
247
6.65k
        if (gs_clip_bounds_in_user_space(ctx->pgs, &clip_bbox) >= 0)
248
6.59k
        {
249
6.59k
            rect_intersect(bbox, clip_bbox);
250
6.59k
            if (bbox.p.x >= bbox.q.x || bbox.p.y >= bbox.q.y)
251
1.11k
            {
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
1.11k
                empty = 1;
256
1.11k
            }
257
6.59k
        }
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
6.65k
        code = pdfi_dict_knownget_type(ctx, G_stream_dict, "Group", PDF_DICT, (pdf_obj **)&Group);
262
6.65k
        if (code < 0)
263
2.44k
            goto exit;
264
4.21k
        if (code > 0) {
265
            /* TODO: Stuff with colorspace, see .execmaskgroup */
266
3.95k
            code = pdfi_dict_knownget(ctx, Group, "CS", &CS);
267
3.95k
            if (code < 0) {
268
36
                code = pdfi_dict_knownget(ctx, Group, "ColorSpace", &CS);
269
36
                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
36
                pdfi_set_warning(ctx, 0, NULL, W_PDF_GROUP_HAS_COLORSPACE, "pdfi_trans_set_mask", NULL);
274
36
            }
275
3.95k
            if (code > 0) {
276
3.87k
                code = pdfi_create_colorspace(ctx, CS, (pdf_dict *)ctx->main_stream,
277
3.87k
                                              ctx->page.CurrentPageDict, &pcs, false);
278
3.87k
                params.ColorSpace = pcs;
279
3.87k
                if (code < 0)
280
135
                    goto exit;
281
3.87k
            }
282
79
            else
283
79
                   params.ColorSpace = NULL;
284
3.95k
        } else {
285
            /* GS and Adobe will ignore the whole mask in this case, so we do the same.
286
            */
287
259
            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
259
            goto exit;
289
259
        }
290
291
        /* If there's a BC, put it in the params */
292
3.82k
        if (BC) {
293
2.38k
            if (params.ColorSpace == NULL) {
294
37
                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
2.34k
            } else {
297
2.34k
                int i, components = pdfi_array_size(BC);
298
2.34k
                double num;
299
2.34k
                int cspace_cmps;
300
301
2.34k
                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
2.34k
                } else {
305
2.34k
                    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
2.34k
                    else {
310
2.34k
                        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
8.33k
                        for (i=0; i < components; i++) {
316
5.99k
                            code = pdfi_array_get_number(ctx, BC, i, &num);
317
5.99k
                            if (code < 0)
318
0
                                break;
319
5.99k
                            params.Background[i] = (float)num;
320
5.99k
                        }
321
2.34k
                        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
2.34k
                        pdfi_set_GrayBackground(&params);
330
2.34k
                    }
331
2.34k
                }
332
2.34k
            }
333
2.38k
        }
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
3.82k
        if (code >= 0) {
354
            /* Override the colorspace if specified */
355
3.82k
            saved_gs = gs_gstate_copy(ctx->pgs, ctx->memory);
356
3.82k
            if (saved_gs == NULL)
357
0
                code = gs_note_error(gs_error_VMerror);
358
3.82k
            if (code >= 0)
359
3.82k
                code = pdfi_gs_setcolorspace(ctx, igs->GroupGState->color[0].color_space);
360
3.82k
            if (code >= 0)
361
3.82k
                code = gs_setcolor(ctx->pgs, igs->GroupGState->color[0].ccolor);
362
3.82k
            gs_swapcolors_quick(ctx->pgs);
363
3.82k
            if (code >= 0)
364
3.82k
                code = pdfi_gs_setcolorspace(ctx, igs->GroupGState->color[1].color_space);
365
3.82k
            if (code >= 0)
366
3.82k
                code = gs_setcolor(ctx->pgs, igs->GroupGState->color[1].ccolor);
367
3.82k
            gs_swapcolors_quick(ctx->pgs);
368
3.82k
        }
369
370
3.82k
        if (code >= 0)
371
3.82k
            code = gs_begin_transparency_mask(ctx->pgs, &params, &bbox, false);
372
373
3.82k
        if (code >= 0) {
374
3.82k
            if (!empty)
375
3.62k
                code = pdfi_form_execgroup(ctx, ctx->page.CurrentPageDict, G_stream,
376
3.62k
                                           igs->GroupGState, NULL, NULL, &group_Matrix);
377
3.82k
            code1 = gs_end_transparency_mask(ctx->pgs, colorindex);
378
3.82k
            if (code == 0)
379
3.82k
                code = code1;
380
3.82k
        }
381
382
3.82k
        if (saved_gs) {
383
3.82k
            code1 = pdfi_gs_setcolorspace(ctx, saved_gs->color[0].color_space);
384
3.82k
            if (code >= 0) code = code1;
385
3.82k
            code1 = gs_setcolor(ctx->pgs, saved_gs->color[0].ccolor);
386
3.82k
            if (code >= 0) code = code1;
387
3.82k
            gs_swapcolors_quick(ctx->pgs);
388
3.82k
            code1 = pdfi_gs_setcolorspace(ctx, saved_gs->color[1].color_space);
389
3.82k
            if (code >= 0) code = code1;
390
3.82k
            code1 = gs_setcolor(ctx->pgs, saved_gs->color[1].ccolor);
391
3.82k
            if (code >= 0) code = code1;
392
3.82k
            gs_swapcolors_quick(ctx->pgs);
393
3.82k
        }
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
3.82k
        gs_setmatrix(ctx->pgs, &save_matrix);
399
400
        /* Set Processed flag */
401
3.82k
        if (code == 0 && ProcessedKnown)
402
3.82k
        {
403
3.82k
            code = pdfi_dict_put_bool(ctx, SMask, "Processed", true);
404
3.82k
            if (code < 0)
405
0
                goto exit;
406
3.82k
        }
407
3.82k
    } else {
408
        /* take action on a non-/Mask entry. What does this mean ? What do we need to do */
409
124
        pdfi_set_warning(ctx, 0, NULL, W_PDF_SMASK_UNKNOWN_TYPE, "pdfi_trans_set_mask", "");
410
124
    }
411
412
14.2k
 exit:
413
14.2k
    gs_gstate_free(saved_gs);
414
14.2k
    gs_setoverrideicc(ctx->pgs, save_OverrideICC);
415
14.2k
    if (gsfunc)
416
431
        pdfi_free_function(ctx, gsfunc);
417
14.2k
    if (pcs)
418
3.74k
        rc_decrement_cs(pcs, "pdfi_trans_set_mask");
419
14.2k
    pdfi_countdown(n);
420
14.2k
    pdfi_countdown(S);
421
14.2k
    pdfi_countdown(Group);
422
14.2k
    pdfi_countdown(G_stream);
423
14.2k
    pdfi_countdown(a);
424
14.2k
    pdfi_countdown(BC);
425
14.2k
    pdfi_countdown(TR);
426
14.2k
    pdfi_countdown(BBox);
427
14.2k
    pdfi_countdown(Matrix);
428
14.2k
    pdfi_countdown(CS);
429
#if DEBUG_TRANSPARENCY
430
    dbgmprintf(ctx->memory, "pdfi_trans_set_mask (.execmaskgroup) END\n");
431
#endif
432
14.2k
    return code;
433
12.2k
}
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
106k
{
440
106k
    if (gs_getalphaisshape(pgs)) {
441
4.76k
        params->group_shape = gs_getfillconstantalpha(pgs);
442
4.76k
        params->group_opacity = 1.0;
443
102k
    } else {
444
102k
        params->group_opacity = gs_getfillconstantalpha(pgs);
445
102k
        params->group_shape = 1.0;
446
102k
    }
447
448
106k
    return gs_begin_transparency_group(pgs, params, pbbox, group_type);
449
106k
}
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
28.4k
{
455
28.4k
    gs_transparency_group_params_t params;
456
28.4k
    pdf_obj *CS = NULL;
457
28.4k
    bool b;
458
28.4k
    int code;
459
460
28.4k
    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
28.4k
    code = pdfi_dict_get_bool(ctx, group_dict, "I", &b);
465
28.4k
    if (code < 0 && code != gs_error_undefined)
466
0
        return_error(code);
467
28.4k
    if (code == gs_error_undefined)
468
8.79k
        params.Isolated = false;
469
19.6k
    else
470
19.6k
        params.Isolated = b;
471
472
    /* It seems the flag for Knockout is /K */
473
28.4k
    code = pdfi_dict_get_bool(ctx, group_dict, "K", &b);
474
28.4k
    if (code < 0 && code != gs_error_undefined)
475
0
        goto exit;
476
28.4k
    if (code == gs_error_undefined)
477
8.99k
        params.Knockout = false;
478
19.4k
    else
479
19.4k
        params.Knockout = b;
480
481
28.4k
    params.image_with_SMask = false;
482
28.4k
    params.ColorSpace = NULL;
483
484
28.4k
    code = pdfi_dict_knownget(ctx, group_dict, "CS", &CS);
485
28.4k
    if (code == 0) {
486
        /* Didn't find a /CS key, try again using /ColorSpace */
487
3.72k
        code = pdfi_dict_knownget(ctx, group_dict, "ColorSpace", &CS);
488
3.72k
    }
489
28.4k
    if (code > 0 && pdfi_type_of(CS) != PDF_NULL) {
490
24.2k
        code = pdfi_setcolorspace(ctx, CS, group_dict, page_dict);
491
24.2k
        if (code < 0)
492
218
            goto exit;
493
24.0k
        params.ColorSpace = gs_currentcolorspace(ctx->pgs);
494
24.0k
    } else {
495
4.17k
        params.ColorSpace = NULL;
496
4.17k
    }
497
498
28.4k
 exit:
499
28.4k
    pdfi_countdown(CS);
500
28.4k
    if (code < 0)
501
380
        return_error(code);
502
503
28.0k
    return pdfi_gs_begin_transparency_group(ctx->pgs, &params, (const gs_rect *)bbox, group_type);
504
28.4k
}
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
20.7k
{
538
20.7k
    gs_transparency_group_params_t params;
539
20.7k
    gs_rect bbox;
540
20.7k
    int code;
541
542
20.7k
    gs_trans_group_params_init(&params, 1.0);
543
20.7k
    params.Isolated = isolated;
544
20.7k
    params.Knockout = knockout;
545
546
20.7k
    if (!pathbbox) {
547
17.4k
        code = pdfi_get_current_bbox(ctx, &bbox, stroked_bbox);
548
17.4k
        if (code < 0)
549
1.76k
            return code;
550
15.6k
        pathbbox = &bbox;
551
15.6k
    }
552
553
19.0k
    code = pdfi_gs_begin_transparency_group(ctx->pgs, &params, pathbbox, PDF14_BEGIN_TRANS_GROUP);
554
19.0k
    if (code >=  0)
555
19.0k
        ctx->current_stream_save.group_depth++;
556
19.0k
    return code;
557
20.7k
}
558
559
int pdfi_trans_begin_page_group(pdf_context *ctx, pdf_dict *page_dict, pdf_dict *group_dict)
560
7.95k
{
561
7.95k
    gs_rect bbox;
562
7.95k
    int code;
563
564
7.95k
    if (group_dict == NULL)
565
0
        return_error(gs_error_undefined);
566
567
7.95k
    code = pdfi_gsave(ctx);
568
7.95k
    bbox.p.x = ctx->page.Size[0];
569
7.95k
    bbox.p.y = ctx->page.Size[1];
570
7.95k
    bbox.q.x = ctx->page.Size[2];
571
7.95k
    bbox.q.y = ctx->page.Size[3];
572
573
7.95k
    code = pdfi_transparency_group_common(ctx, page_dict, group_dict, &bbox, PDF14_BEGIN_TRANS_PAGE_GROUP);
574
7.95k
    if (code < 0)
575
147
        pdfi_grestore(ctx);
576
7.81k
    else
577
7.81k
        ctx->current_stream_save.group_depth++;
578
579
7.95k
    return code;
580
7.95k
}
581
582
int pdfi_trans_begin_form_group(pdf_context *ctx, pdf_dict *page_dict, pdf_dict *form_dict)
583
21.5k
{
584
21.5k
    pdf_obj *group_obj = NULL;
585
21.5k
    gs_rect bbox;
586
21.5k
    pdf_array *BBox = NULL;
587
21.5k
    int code;
588
21.5k
    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
21.5k
    code = pdfi_dict_get(ctx, form_dict, "Group", &group_obj);
595
21.5k
    if (code < 0)
596
495
        return_error(code);
597
598
21.0k
    code = pdfi_dict_from_obj(ctx, (pdf_obj *)group_obj, &group_dict);
599
21.0k
    if (code < 0)
600
544
        goto exit;
601
602
20.4k
    code = pdfi_gsave(ctx);
603
20.4k
    code = pdfi_dict_knownget_type(ctx, form_dict, "BBox", PDF_ARRAY, (pdf_obj **)&BBox);
604
20.4k
    if (code < 0)
605
0
        goto exit;
606
20.4k
    if (code > 0) {
607
20.4k
        code = pdfi_array_to_gs_rect(ctx, BBox, &bbox);
608
20.4k
        if (code < 0)
609
0
            goto exit;
610
20.4k
    } else {
611
2
        bbox.p.x = 0;
612
2
        bbox.p.y = 0;
613
2
        bbox.q.x = 0;
614
2
        bbox.q.y = 0;
615
2
    }
616
617
20.4k
    code = pdfi_transparency_group_common(ctx, page_dict, group_dict, &bbox, PDF14_BEGIN_TRANS_GROUP);
618
20.4k
    if (code < 0)
619
233
        pdfi_grestore(ctx);
620
20.2k
    else
621
20.2k
        ctx->current_stream_save.group_depth++;
622
623
21.0k
 exit:
624
21.0k
    pdfi_countdown(BBox);
625
21.0k
    pdfi_countdown(group_obj);
626
21.0k
    return code;
627
20.4k
}
628
629
630
int pdfi_trans_end_group(pdf_context *ctx)
631
28.0k
{
632
28.0k
    int code;
633
634
28.0k
    code = gs_end_transparency_group(ctx->pgs);
635
28.0k
    if (code < 0)
636
0
        pdfi_grestore(ctx);
637
28.0k
    else
638
28.0k
        code = pdfi_grestore(ctx);
639
640
28.0k
    ctx->current_stream_save.group_depth--;
641
642
28.0k
    return code;
643
28.0k
}
644
645
/* Ends group with no grestore */
646
int pdfi_trans_end_simple_group(pdf_context *ctx)
647
19.0k
{
648
19.0k
    int code;
649
650
19.0k
    code = gs_end_transparency_group(ctx->pgs);
651
19.0k
    ctx->current_stream_save.group_depth--;
652
653
19.0k
    return code;
654
19.0k
}
655
656
657
int pdfi_trans_begin_isolated_group(pdf_context *ctx, bool image_with_SMask, gs_color_space *pcs)
658
59.7k
{
659
59.7k
    gs_transparency_group_params_t params;
660
59.7k
    gs_rect bbox;
661
59.7k
    gs_rect clip_box;
662
663
59.7k
    gs_trans_group_params_init(&params, 1.0);
664
665
59.7k
    params.ColorSpace = pcs;
666
59.7k
    params.Isolated = true;
667
59.7k
    params.Knockout = false;
668
59.7k
    params.image_with_SMask = image_with_SMask;
669
59.7k
    bbox.p.x = 0;
670
59.7k
    bbox.p.y = 0;
671
59.7k
    bbox.q.x = 1;
672
59.7k
    bbox.q.y = 1;
673
59.7k
    if (gs_clip_bounds_in_user_space(ctx->pgs, &clip_box) >= 0)
674
59.7k
        rect_intersect(bbox, clip_box);
675
676
59.7k
    return pdfi_gs_begin_transparency_group(ctx->pgs, &params, &bbox, PDF14_BEGIN_TRANS_GROUP);
677
59.7k
}
678
679
int pdfi_trans_end_isolated_group(pdf_context *ctx)
680
59.7k
{
681
59.7k
    return gs_end_transparency_group(ctx->pgs);
682
59.7k
}
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
68.1k
{
690
68.1k
    gs_transparency_mask_params_t params;
691
68.1k
    gs_rect bbox;
692
693
68.1k
    gs_trans_mask_params_init(&params, TRANSPARENCY_MASK_None);
694
68.1k
    params.replacing = true;
695
696
68.1k
    bbox.p.x = 0;
697
68.1k
    bbox.p.y = 0;
698
68.1k
    bbox.q.x = 0;
699
68.1k
    bbox.q.y = 0;
700
701
68.1k
    return gs_begin_transparency_mask(ctx->pgs, &params, &bbox, false);
702
68.1k
}
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
136k
{
715
136k
    bool is_cmyk;
716
136k
    bool device_transparency = false;
717
718
    /* PS code checks for >= 4 components... */
719
136k
    is_cmyk = ctx->pgs->device->color_info.num_components >= 4 && ctx->pgs->device->color_info.polarity == GX_CINFO_POLARITY_SUBTRACTIVE;
720
721
136k
    device_transparency = pdfi_device_check_param_bool(ctx->pgs->device, "HaveTransparency");
722
723
136k
    ctx->page.needs_OP = false;
724
136k
    ctx->page.simulate_op = false;
725
136k
    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
136k
    case gs_overprint_control_enable:
748
136k
    default:
749
136k
        if (!is_cmyk || device_transparency)
750
117k
            ctx->page.needs_OP = false;
751
18.9k
        else
752
18.9k
            ctx->page.needs_OP = true;
753
136k
        break;
754
136k
    }
755
756
136k
    if(ctx->args.pdfdebug)
757
136k
        dbgmprintf2(ctx->memory, "Page %s Overprint, Simulate is %s\n",
758
136k
                    ctx->page.needs_OP ? "NEEDS" : "does NOT NEED",
759
136k
                    ctx->page.simulate_op ? "TRUE" : "FALSE");
760
136k
}
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
331k
{
765
331k
    gs_color_space_index csi;
766
767
331k
    csi = pdfi_currentcolorspace(ctx, 0);
768
769
331k
    switch (csi) {
770
55.6k
    case gs_color_space_index_DeviceGray:
771
82.0k
    case gs_color_space_index_DeviceCMYK:
772
82.3k
    case gs_color_space_index_DeviceN:
773
84.0k
    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
84.0k
        return true;
783
247k
    default:
784
#if DEBUG_TRANSPARENCY
785
        dbgmprintf1(ctx->memory, "Colorspace is %d, NOT OKAY for OVERPRINT\n", csi);
786
#endif
787
247k
        return false;
788
331k
    }
789
790
0
    return false;
791
331k
}
792
793
int pdfi_trans_setup(pdf_context *ctx, pdfi_trans_state_t *state, gs_rect *bbox,
794
                           pdfi_transparency_caller_t caller)
795
8.65M
{
796
8.65M
    pdfi_int_gstate *igs = (pdfi_int_gstate *)ctx->pgs->client_data;
797
8.65M
    int code;
798
8.65M
    bool stroked_bbox;
799
8.65M
    bool current_overprint;
800
8.65M
    bool okOPcs = false;
801
8.65M
    bool ChangeBM = false;
802
8.65M
    gs_blend_mode_t  mode = gs_currentblendmode(ctx->pgs);  /* quite warning */
803
8.65M
    bool need_group = false;
804
805
8.65M
    memset(state, 0, sizeof(*state));
806
807
8.65M
    if (!ctx->page.has_transparency)
808
6.85M
        return 0;
809
810
1.79M
    if (ctx->page.needs_OP) {
811
321k
        okOPcs = pdfi_trans_okOPcs(ctx);
812
321k
        if (okOPcs) {
813
84.0k
            if (caller == TRANSPARENCY_Caller_Stroke)
814
35.2k
                current_overprint = gs_currentstrokeoverprint(ctx->pgs);
815
48.7k
            else {
816
48.7k
                current_overprint = gs_currentfilloverprint(ctx->pgs);
817
48.7k
                if (caller == TRANSPARENCY_Caller_FillStroke)
818
1.53k
                    current_overprint |= gs_currentstrokeoverprint(ctx->pgs);
819
48.7k
            }
820
84.0k
            ChangeBM = current_overprint;
821
84.0k
            mode = gs_currentblendmode(ctx->pgs);
822
84.0k
            if (mode != BLEND_MODE_Normal && mode != BLEND_MODE_Compatible)
823
931
                need_group = ChangeBM;
824
83.0k
            else
825
83.0k
                need_group = false;
826
237k
        } else {
827
237k
            need_group = false;
828
237k
        }
829
321k
        need_group = need_group || (igs->SMask != NULL);
830
1.47M
    } else {
831
1.47M
        if (caller == TRANSPARENCY_Caller_Image || igs->SMask == NULL)
832
1.46M
            need_group = false;
833
10.2k
        else
834
10.2k
            need_group = true;
835
1.47M
    }
836
837
1.79M
    code = pdfi_trans_set_params(ctx);
838
1.79M
    if (code != 0)
839
2.67k
        return 0;
840
841
1.79M
    if (!need_group && !ChangeBM)
842
1.78M
        return 0;
843
844
    /* TODO: error handling... */
845
14.2k
    if (need_group) {
846
8.86k
        bool isolated = false;
847
8.86k
        mode = gs_currentblendmode(ctx->pgs);
848
849
8.86k
        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
8.86k
        if (igs->SMask != NULL && mode != BLEND_MODE_Normal && mode != BLEND_MODE_Compatible)
855
4.68k
            isolated = true;
856
8.86k
        code = pdfi_trans_begin_simple_group(ctx, bbox, stroked_bbox, isolated, false);
857
858
        /* Group was not pushed if error */
859
8.86k
        if (code >= 0)
860
7.09k
            state->GroupPushed = true;
861
862
8.86k
        state->saveStrokeAlpha = gs_getstrokeconstantalpha(ctx->pgs);
863
8.86k
        state->saveFillAlpha = gs_getfillconstantalpha(ctx->pgs);
864
8.86k
        code = gs_setfillconstantalpha(ctx->pgs, 1.0);
865
8.86k
        code = gs_setstrokeconstantalpha(ctx->pgs, 1.0);
866
8.86k
    }
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
14.2k
    if (ChangeBM && caller != TRANSPARENCY_Caller_FillStroke) {
873
5.72k
        state->saveBM = mode;
874
5.72k
        state->ChangeBM = true;
875
5.72k
        code = gs_setblendmode(ctx->pgs, BLEND_MODE_CompatibleOverprint);
876
5.72k
    }
877
14.2k
    return code;
878
1.79M
}
879
880
int pdfi_trans_required(pdf_context *ctx)
881
54.3M
{
882
54.3M
    gs_blend_mode_t mode;
883
884
54.3M
    if (!ctx->page.has_transparency)
885
42.0M
        return 0;
886
887
12.2M
    mode = gs_currentblendmode(ctx->pgs);
888
12.2M
    if ((mode == BLEND_MODE_Normal || mode == BLEND_MODE_Compatible) &&
889
12.2M
        ctx->pgs->fillconstantalpha == 1 &&
890
12.1M
        ctx->pgs->strokeconstantalpha == 1 &&
891
12.1M
        ((pdfi_int_gstate *)ctx->pgs->client_data)->SMask == NULL)
892
12.1M
        return 0;
893
894
60.9k
    return 1;
895
12.2M
}
896
897
int pdfi_trans_setup_text(pdf_context *ctx, pdfi_trans_state_t *state, bool is_show)
898
26.8M
{
899
26.8M
    int Trmode;
900
26.8M
    int code, code1;
901
26.8M
    gs_rect bbox;
902
903
26.8M
    if (!pdfi_trans_required(ctx))
904
26.8M
        return 0;
905
906
23.6k
    Trmode = gs_currenttextrenderingmode(ctx->pgs);
907
23.6k
    code = gs_gsave(ctx->pgs);
908
23.6k
    if (code < 0) goto exit;
909
910
23.6k
    if (is_show) {
911
23.6k
        code = gs_clippath(ctx->pgs);
912
23.6k
    } else {
913
0
        code = gs_strokepath(ctx->pgs);
914
0
    }
915
23.6k
    if (code >= 0)
916
23.6k
        code = gs_upathbbox(ctx->pgs, &bbox, false);
917
23.6k
    if (code < 0) {
918
        /* Just set bbox to [0,0,0,0] */
919
39
        bbox.p.x = bbox.p.y = bbox.q.x = bbox.q.y = 0.0;
920
39
        code = 0;
921
39
    }
922
23.6k
    code1 = gs_grestore(ctx->pgs);
923
23.6k
    if (code == 0) code = code1;
924
23.6k
    if (code < 0) goto exit;
925
926
23.6k
    switch (Trmode) {
927
23.6k
    case 0:
928
23.6k
        code = pdfi_trans_setup(ctx, state, &bbox, TRANSPARENCY_Caller_Fill);
929
23.6k
        break;
930
68
    default:
931
        /* TODO: All the others */
932
68
        code = pdfi_trans_setup(ctx, state, &bbox, TRANSPARENCY_Caller_Fill);
933
68
        break;
934
23.6k
    }
935
936
23.6k
 exit:
937
23.6k
    return code;
938
23.6k
}
939
940
int pdfi_trans_teardown_text(pdf_context *ctx, pdfi_trans_state_t *state)
941
26.8M
{
942
26.8M
    if (!pdfi_trans_required(ctx))
943
26.8M
         return 0;
944
945
23.6k
    return pdfi_trans_teardown(ctx, state);
946
26.8M
}
947
948
int pdfi_trans_teardown(pdf_context *ctx, pdfi_trans_state_t *state)
949
8.65M
{
950
8.65M
    int code = 0;
951
952
8.65M
    if (!ctx->page.has_transparency)
953
6.85M
        return 0;
954
955
1.79M
    if (state->GroupPushed) {
956
7.09k
        code = pdfi_trans_end_simple_group(ctx);
957
7.09k
        code = gs_setstrokeconstantalpha(ctx->pgs, state->saveStrokeAlpha);
958
7.09k
        code = gs_setfillconstantalpha(ctx->pgs, state->saveFillAlpha);
959
7.09k
    }
960
961
1.79M
    if (gs_currentblendmode(ctx->pgs) == BLEND_MODE_CompatibleOverprint)
962
5.72k
        code = gs_setblendmode(ctx->pgs, state->saveBM);
963
964
1.79M
    return code;
965
8.65M
}
966
967
int pdfi_trans_set_params(pdf_context *ctx)
968
2.45M
{
969
2.45M
    int code = 0;
970
2.45M
    pdfi_int_gstate *igs = (pdfi_int_gstate *)ctx->pgs->client_data;
971
2.45M
    gs_transparency_channel_selector_t csel;
972
973
2.45M
    if (ctx->page.has_transparency) {
974
2.14M
        if (gs_getalphaisshape(ctx->pgs))
975
10.0k
            csel = TRANSPARENCY_CHANNEL_Shape;
976
2.13M
        else
977
2.13M
            csel = TRANSPARENCY_CHANNEL_Opacity;
978
2.14M
        if (igs->SMask) {
979
14.2k
            code = pdfi_trans_set_mask(ctx, igs, csel);
980
14.2k
        }
981
2.14M
    }
982
983
2.45M
    return code;
984
2.45M
}