Coverage Report

Created: 2026-08-08 08:00

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