Coverage Report

Created: 2026-04-09 07:06

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