Coverage Report

Created: 2025-06-10 07:27

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