Coverage Report

Created: 2025-08-28 07:06

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