Coverage Report

Created: 2022-10-31 07:00

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