Coverage Report

Created: 2026-07-24 07:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/base/gstrans.c
Line
Count
Source
1
/* Copyright (C) 2001-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
17
/* Implementation of transparency, other than rendering */
18
#include "math_.h"
19
#include "memory_.h"
20
#include "gx.h"
21
#include "gserrors.h"
22
#include "gstrans.h"
23
#include "gsutil.h"
24
#include "gzstate.h"
25
#include "gxdevcli.h"
26
#include "gdevdevn.h"
27
#include "gxblend.h"
28
#include "gdevp14.h"
29
#include "gscspace.h"
30
#include "gxarith.h"
31
#include "gxclist.h"
32
#include "gsicc_manage.h"
33
#include "gsicc_cache.h"
34
#include "gxdevsop.h"
35
36
/* ------ Transparency-related graphics state elements ------ */
37
38
int
39
gs_setblendmode(gs_gstate *pgs, gs_blend_mode_t mode)
40
1.64M
{
41
#ifdef DEBUG
42
    if (gs_debug_c('v')) {
43
        static const char *const bm_names[] = { GS_BLEND_MODE_NAMES };
44
45
        dmlprintf1(pgs->memory, "[v]("PRI_INTPTR")blend_mode = ", (intptr_t)pgs);
46
        if (mode >= 0 && mode < countof(bm_names))
47
            dmprintf1(pgs->memory, "%s\n", bm_names[mode]);
48
        else
49
            dmprintf1(pgs->memory, "%d??\n", (int)mode);
50
    }
51
#endif
52
    /* Map Compatible to Normal so other code treats Compatible as Normal */
53
    /* Often BLEND_MODE_Normal is checked for optimized handling, and     */
54
    /* Compatible is now specified to be the same.                        */
55
1.64M
    if (mode == BLEND_MODE_Compatible)
56
1.46M
        mode = BLEND_MODE_Normal;
57
1.64M
    if ((int)mode < 0 || (int)mode > MAX_BLEND_MODE)
58
0
        return_error(gs_error_rangecheck);
59
1.64M
    pgs->blend_mode = mode;
60
1.64M
    return 0;
61
1.64M
}
62
63
gs_blend_mode_t
64
gs_currentblendmode(const gs_gstate *pgs)
65
14.1M
{
66
14.1M
    return pgs->blend_mode;
67
14.1M
}
68
69
int
70
gs_settextknockout(gs_gstate *pgs, bool knockout)
71
1.44M
{
72
1.44M
    if_debug2m('v', pgs->memory, "[v]("PRI_INTPTR")text_knockout = %s\n",
73
1.44M
              (intptr_t)pgs, (knockout ? "true" : "false"));
74
1.44M
    pgs->text_knockout = knockout;
75
1.44M
    return 0;
76
1.44M
}
77
78
bool
79
gs_currenttextknockout(const gs_gstate *pgs)
80
2.92M
{
81
2.92M
    return pgs->text_knockout;
82
2.92M
}
83
84
/* This is used to keep pdf14 compositor actions from the interpreter from
85
   corrupting pattern renderings.  For example, if the file has a softmask,
86
   the intrepter will send push and pop transparency state commands when
87
   q and Q operations are encountered.  If we are writing out to a pattern
88
   clist that has no trasparency we do not want these state changes to
89
   be entered as compositor actions in the pattern clist */
90
91
static int
92
check_for_nontrans_pattern(gs_gstate *pgs, unsigned char *comp_name)
93
2.99M
{
94
2.99M
    gx_device * dev = pgs->device;
95
2.99M
    bool is_patt_clist = gx_device_is_pattern_clist(dev);
96
2.99M
    bool is_patt_acum = gx_device_is_pattern_accum(dev);
97
98
    /* Check if we are collecting data for a pattern that has no
99
       transparency.  In that case, we need to ignore the state changes */
100
2.99M
    if (is_patt_clist || is_patt_acum) {
101
5.60k
        if (is_patt_clist) {
102
672
            gx_device_clist_writer *clwdev = (gx_device_clist_writer*) dev;
103
672
            const gs_pattern1_instance_t *pinst = clwdev->pinst;
104
105
672
            if (!(pinst->templat.uses_transparency)) {
106
672
                if_debug1m('v', pgs->memory,
107
672
                           "[v]%s NOT sending in pattern\n",comp_name);
108
672
                return(1);
109
672
            }
110
672
        }
111
4.92k
        if (is_patt_acum) {
112
4.92k
            gx_device_pattern_accum *padev = (gx_device_pattern_accum*) dev;
113
4.92k
            const gs_pattern1_instance_t *pinst = padev->instance;
114
115
4.92k
            if (!(pinst->templat.uses_transparency)) {
116
4.92k
                if_debug1m('v', pgs->memory,
117
4.92k
                           "[v]%s NOT sending in pattern\n",comp_name);
118
4.92k
                return(1);
119
4.92k
            }
120
4.92k
        }
121
4.92k
    }
122
2.98M
    return(0);
123
2.99M
}
124
125
/*
126
 * Push a PDF 1.4 transparency compositor onto the current device. Note that
127
 * if the current device already is a PDF 1.4 transparency compositor, the
128
 * composite will update its parameters but not create a new
129
 * compositor device.
130
 */
131
static int
132
gs_gstate_update_pdf14trans2(gs_gstate * pgs, gs_pdf14trans_params_t * pparams, bool retain_on_create)
133
1.17M
{
134
1.17M
    gx_device * dev = pgs->device;
135
1.17M
    gx_device *pdf14dev = NULL;
136
1.17M
    int code;
137
1.17M
    int curr_num = dev->color_info.num_components;
138
139
    /*
140
     * Send the PDF 1.4 create compositor action specified by the parameters.
141
     */
142
1.17M
    code = send_pdf14trans(pgs, dev, &pdf14dev, pparams, pgs->memory);
143
1.17M
    if (code < 0)
144
19.1k
        return code;
145
    /*
146
     * If we created a new PDF 1.4 compositor device then we need to install it
147
     * into the graphics state.
148
     */
149
1.15M
    if (code == 1) {
150
16.6k
        gx_set_device_only(pgs, pdf14dev);
151
16.6k
        gx_device_retain(pdf14dev, retain_on_create);
152
16.6k
        code = 0;
153
16.6k
    }
154
155
    /* If we had a color space change and we are in overprint, then we need to
156
       update the drawn_comps */
157
1.15M
    if (pgs->overprint && curr_num != pdf14dev->color_info.num_components) {
158
190
        code = gs_do_set_overprint(pgs);
159
190
    }
160
161
1.15M
    return code;
162
1.17M
}
163
164
static int
165
gs_gstate_update_pdf14trans(gs_gstate * pgs, gs_pdf14trans_params_t * pparams)
166
1.15M
{
167
1.15M
    return gs_gstate_update_pdf14trans2(pgs, pparams, true);
168
1.15M
}
169
170
void
171
gs_trans_group_params_init(gs_transparency_group_params_t *ptgp, float opacity)
172
48.0k
{
173
48.0k
    ptgp->ColorSpace = NULL;    /* bogus, but can't do better */
174
48.0k
    ptgp->Isolated = false;
175
48.0k
    ptgp->Knockout = false;
176
48.0k
    ptgp->page_group = false;
177
48.0k
    ptgp->text_group = PDF14_TEXTGROUP_NO_BT;
178
48.0k
    ptgp->image_with_SMask = false;
179
48.0k
    ptgp->mask_id = 0;
180
48.0k
    ptgp->iccprofile = NULL;
181
48.0k
    ptgp->group_opacity = opacity;
182
48.0k
    ptgp->group_shape = 1.0;
183
48.0k
    ptgp->shade_group = false;
184
48.0k
}
185
186
int
187
gs_update_trans_marking_params(gs_gstate * pgs)
188
19.0k
{
189
19.0k
    gs_pdf14trans_params_t params = { 0 };
190
19.0k
    int code;
191
192
19.0k
    if_debug0m('v', pgs->memory, "[v]gs_update_trans_marking_params\n");
193
19.0k
    params.pdf14_op = PDF14_SET_BLEND_PARAMS;
194
19.0k
    code = gs_gstate_update_pdf14trans(pgs, &params);
195
19.0k
    if (code == gs_error_unregistered)
196
19.0k
        code = 0;
197
19.0k
    return code;
198
19.0k
}
199
200
int
201
gs_begin_transparency_group(gs_gstate *pgs,
202
                            const gs_transparency_group_params_t *ptgp,
203
                            const gs_rect *pbbox, pdf14_compositor_operations group_type)
204
68.5k
{
205
68.5k
    gs_pdf14trans_params_t params = { 0 };
206
68.5k
    const gs_color_space *blend_color_space;
207
68.5k
    cmm_profile_t *profile;
208
209
68.5k
    if (check_for_nontrans_pattern(pgs,
210
68.5k
                  (unsigned char *)"gs_begin_transparency_group")) {
211
0
        return(0);
212
0
    }
213
    /*
214
     * Put parameters into a compositor parameter and then call the
215
     * composite.  This will pass the data to the PDF 1.4
216
     * transparency device.
217
     */
218
68.5k
    params.pdf14_op = group_type;
219
68.5k
    params.Isolated = ptgp->Isolated;
220
68.5k
    params.Knockout = ptgp->Knockout;
221
68.5k
    if (group_type == PDF14_BEGIN_TRANS_PAGE_GROUP)
222
4.39k
        params.page_group = true;
223
68.5k
    params.image_with_SMask = ptgp->image_with_SMask;
224
68.5k
    params.opacity = ptgp->group_opacity;
225
68.5k
    params.shape = ptgp->group_shape;
226
68.5k
    params.blend_mode = pgs->blend_mode;
227
68.5k
    params.text_group = ptgp->text_group;
228
68.5k
    params.shade_group = ptgp->shade_group;
229
68.5k
    params.ColorSpace = ptgp->ColorSpace;
230
    /* This function is called during the c-list writer side.
231
       Store some information so that we know what the color space is
232
       so that we can adjust according later during the clist reader.
233
       We currently will use the concrete space for any space other than a
234
       device space.  However, if the device is a sep device it will blend
235
       in DeviceN color space as required.  */
236
68.5k
    blend_color_space = gs_currentcolorspace_inline(pgs);
237
68.5k
    if (gs_color_space_get_index(blend_color_space) > gs_color_space_index_DeviceCMYK) {
238
        /* ICC and PS CIE based case.  Note that unidirectional PS CIE color
239
           spaces should not be allowed but end up occuring when processing
240
           PDF files with -dUseCIEColor.  We will end up using the appropriate
241
           ICC default color space in these cases. */
242
68.5k
        blend_color_space = gs_currentcolorspace_inline(pgs);
243
68.5k
    } else {
244
0
        blend_color_space = cs_concrete_space(blend_color_space, pgs);
245
0
        if (!blend_color_space)
246
0
            return_error(gs_error_undefined);
247
0
    }
248
    /* Note that if the /CS parameter was NOT present in the push
249
       of the transparency group, then we must actually inherent
250
       the previous group color space, or the color space of the
251
       target device (process color model).  Here we just want
252
       to set it as a unknown type for clist writing, as we will take care
253
       of using the parent group color space later during clist reading.
254
       Also, if the group was not isolated we MUST use the parent group
255
       color space regardless of what the group color space is specified to be.
256
       Note that the page group should always be isolated */
257
68.5k
    if (group_type == PDF14_BEGIN_TRANS_PAGE_GROUP)
258
4.39k
        params.Isolated = true;
259
260
68.5k
    if (ptgp->ColorSpace == NULL || params.Isolated != true) {
261
63.5k
        params.group_color_type = UNKNOWN;
262
63.5k
        params.group_color_numcomps = 0;
263
63.5k
    } else {
264
        /* The /CS parameter was present.  Use what was set.  Currently
265
           all our Device spaces are actually ICC based.  The other options
266
           are if -dUseCIEColor is set, in which case it could be
267
           coming in as a PS CIE color space, which should not be allowed
268
           but should default to one of the default ICC color spaces.  Note
269
           that CalRGB and CalGray, which are valid bidirectional color spaces
270
           are converted to ICC profiles during installation. PS CIE building
271
           to ICC is delayed. */
272
4.99k
        if ( gs_color_space_is_ICC(blend_color_space) ) {
273
            /* Blending space is ICC based.  If we are doing c-list rendering
274
               we will need to write this color space into the clist.
275
               */
276
4.99k
            params.group_color_type = ICC;
277
4.99k
            params.group_color_numcomps =
278
4.99k
                blend_color_space->cmm_icc_profile_data->num_comps;
279
            /* Get the ICC profile */
280
4.99k
            params.iccprofile = blend_color_space->cmm_icc_profile_data;
281
4.99k
            params.icc_hash = gsicc_get_hash(blend_color_space->cmm_icc_profile_data);
282
4.99k
        } else {
283
            /* Color space was NOT ICC based.  PS CIE space and DeviceN are the only
284
               other option.  Use the ICC default based upon the component count. */
285
0
            switch (cs_num_components(blend_color_space)) {
286
0
                case 1:
287
0
                    profile =  pgs->icc_manager->default_gray;
288
0
                    break;
289
0
                case 3:
290
0
                    profile =  pgs->icc_manager->default_rgb;
291
0
                    break;
292
0
                case 4:
293
0
                    profile =  pgs->icc_manager->default_cmyk;
294
0
                break;
295
0
                default:
296
                    /* We can end up here if we are in a deviceN color space and
297
                       we have a sep output device */
298
0
                    profile = NULL;
299
0
                    params.group_color_type = DEVICEN;
300
0
                    params.group_color_numcomps = cs_num_components(blend_color_space);
301
0
                break;
302
0
            }
303
0
            if (profile != NULL) {
304
0
                params.group_color_type = ICC;
305
0
                params.group_color_numcomps = profile->num_comps;
306
0
                params.iccprofile = profile;
307
0
                params.icc_hash = gsicc_get_hash(profile);
308
0
            }
309
0
        }
310
4.99k
    }
311
#ifdef DEBUG
312
    if (gs_debug_c('v')) {
313
        static const char *const cs_names[] = {
314
            GS_COLOR_SPACE_TYPE_NAMES
315
        };
316
        dmlprintf6(pgs->memory, "[v]("PRI_INTPTR")begin_transparency_group [%g %g %g %g] Num_grp_clr_comp = %d\n",
317
                   (intptr_t)pgs, pbbox->p.x, pbbox->p.y, pbbox->q.x, pbbox->q.y,params.group_color_numcomps);
318
        if (ptgp->ColorSpace)
319
            dmprintf1(pgs->memory, "     CS = %s",
320
                cs_names[(int)gs_color_space_get_index(ptgp->ColorSpace)]);
321
        else
322
            dmputs(pgs->memory, "     (no CS)");
323
324
        dmprintf4(pgs->memory, "  Isolated = %d  Knockout = %d text_group = %d page_group = %d\n",
325
                 ptgp->Isolated, ptgp->Knockout, ptgp->text_group, ptgp->page_group);
326
    }
327
#endif
328
68.5k
    params.bbox = *pbbox;
329
68.5k
    return gs_gstate_update_pdf14trans(pgs, &params);
330
68.5k
}
331
332
int
333
gx_begin_transparency_group(gs_gstate * pgs, gx_device * pdev,
334
                                const gs_pdf14trans_params_t * pparams)
335
1.95M
{
336
1.95M
    gs_transparency_group_params_t tgp = {0};
337
1.95M
    gs_rect bbox;
338
339
1.95M
    if (pparams->Background_components != 0 &&
340
0
        pparams->Background_components != pdev->color_info.num_components)
341
0
        return_error(gs_error_rangecheck);
342
1.95M
    tgp.Isolated = pparams->Isolated;
343
1.95M
    tgp.Knockout = pparams->Knockout;
344
1.95M
    tgp.page_group = pparams->page_group;
345
1.95M
    tgp.idle = pparams->idle;
346
1.95M
    tgp.mask_id = pparams->mask_id;
347
1.95M
    tgp.text_group = pparams->text_group;
348
1.95M
    tgp.shade_group = pparams->shade_group;
349
350
    /* Needed so that we do proper blending */
351
1.95M
    tgp.group_color_type = pparams->group_color_type;
352
1.95M
    tgp.group_color_numcomps = pparams->group_color_numcomps;
353
1.95M
    tgp.iccprofile = pparams->iccprofile;
354
1.95M
    tgp.icc_hashcode = pparams->icc_hash;
355
356
1.95M
    tgp.group_opacity = pparams->opacity;
357
1.95M
    tgp.group_shape = pparams->shape;
358
359
1.95M
    if (tgp.Knockout && tgp.text_group == PDF14_TEXTGROUP_BT_PUSHED &&
360
386k
        ((pgs->overprint && pgs->is_fill_color) || (pgs->stroke_overprint && !pgs->is_fill_color)))
361
3.89k
        pgs->blend_mode = BLEND_MODE_CompatibleOverprint;
362
1.95M
    else
363
1.95M
        pgs->blend_mode = pparams->blend_mode;
364
1.95M
    bbox = pparams->bbox;
365
#ifdef DEBUG
366
    if (gs_debug_c('v')) {
367
        static const char *const cs_names[] = {
368
            GS_COLOR_SPACE_TYPE_NAMES
369
        };
370
        dmlprintf6(pdev->memory, "[v]("PRI_INTPTR")gx_begin_transparency_group [%g %g %g %g] Num_grp_clr_comp = %d\n",
371
                   (intptr_t)pgs, bbox.p.x, bbox.p.y, bbox.q.x, bbox.q.y,
372
                   pparams->group_color_numcomps);
373
        dmlprintf2(pdev->memory, "     opacity = %g shape = %g\n", pparams->opacity, pparams->shape);
374
        if (tgp.ColorSpace)
375
            dmprintf1(pdev->memory, "     CS = %s",
376
                cs_names[(int)gs_color_space_get_index(tgp.ColorSpace)]);
377
        else
378
            dmputs(pdev->memory, "     (no CS)");
379
        dmprintf3(pdev->memory, "  Isolated = %d  Knockout = %d  page_group = %d\n",
380
                 tgp.Isolated, tgp.Knockout, tgp.page_group);
381
        if (tgp.iccprofile)
382
            dmprintf(pdev->memory, "     Have ICC Profile for blending\n");
383
384
    }
385
#endif
386
1.95M
    return (*dev_proc(pdev, begin_transparency_group)) (pdev, &tgp, &bbox, pgs,
387
1.95M
                                                            NULL);
388
1.95M
}
389
390
int
391
gs_end_transparency_group(gs_gstate *pgs)
392
66.2k
{
393
66.2k
    gs_pdf14trans_params_t params = { 0 };
394
395
66.2k
    if (check_for_nontrans_pattern(pgs,
396
66.2k
                  (unsigned char *)"gs_end_transparency_group")) {
397
0
        return(0);
398
0
    }
399
66.2k
    if_debug0m('v', pgs->memory, "[v]gs_end_transparency_group\n");
400
66.2k
    params.pdf14_op = PDF14_END_TRANS_GROUP;  /* Other parameters not used */
401
66.2k
    return gs_gstate_update_pdf14trans(pgs, &params);
402
66.2k
}
403
404
int
405
gs_end_transparency_text_group(gs_gstate *pgs)
406
435k
{
407
435k
    gs_pdf14trans_params_t params = { 0 };
408
409
435k
    if (check_for_nontrans_pattern(pgs,
410
435k
        (unsigned char *)"gs_end_transparency_text_group")) {
411
0
        return(0);
412
0
    }
413
435k
    if_debug0m('v', pgs->memory, "[v]gs_end_transparency_text_group\n");
414
435k
    params.pdf14_op = PDF14_END_TRANS_TEXT_GROUP;  /* Other parameters not used */
415
435k
    return gs_gstate_update_pdf14trans(pgs, &params);
416
435k
}
417
418
int
419
gs_begin_transparency_text_group(gs_gstate *pgs)
420
429k
{
421
429k
    gs_pdf14trans_params_t params = { 0 };
422
423
429k
    if (check_for_nontrans_pattern(pgs,
424
429k
        (unsigned char *)"gs_begin_transparency_text_group")) {
425
0
        return(0);
426
0
    }
427
429k
    if_debug0m('v', pgs->memory, "[v]gs_begin_transparency_text_group\n");
428
429k
    params.pdf14_op = PDF14_BEGIN_TRANS_TEXT_GROUP;  /* Other parameters not used */
429
429k
    return gs_gstate_update_pdf14trans(pgs, &params);
430
429k
}
431
432
int
433
gx_end_transparency_group(gs_gstate * pgs, gx_device * pdev)
434
1.95M
{
435
1.95M
    if_debug0m('v', pgs->memory, "[v]gx_end_transparency_group\n");
436
1.95M
    return (*dev_proc(pdev, end_transparency_group)) (pdev, pgs);
437
1.95M
}
438
439
/* Commands for handling q softmask Q in graphic states */
440
441
int
442
gs_push_transparency_state(gs_gstate *pgs)
443
983k
{
444
983k
    gs_pdf14trans_params_t params = { 0 };
445
983k
    int code;
446
447
983k
    if (check_for_nontrans_pattern(pgs,
448
983k
                  (unsigned char *)"gs_push_transparency_state")) {
449
2.81k
        return(0);
450
2.81k
    }
451
    /* Set the pending flag to true, which indicates
452
       that we need to watch for end transparency
453
       soft masks when we are at this graphic state
454
       level */
455
    /* pgs->trans_flags.xstate_pending = true; */
456
    /* Actually I believe the above flag is not
457
       needed.  We really should be watching for
458
       the softmask even at the base level.  What
459
       we need to watch for are q operations after
460
       a soft mask end has occured. */
461
    /* Check if we have a change flag set to true.
462
       this indicates that a softmask is present.
463
       We will need to send a push state to save
464
       the current soft mask, so that we can
465
       restore it later */
466
980k
    if (pgs->trans_flags.xstate_change) {
467
0
        if_debug0m('v', pgs->memory, "[v]gs_push_transparency_state sending\n");
468
0
        params.pdf14_op = PDF14_PUSH_TRANS_STATE;
469
0
        code = gs_gstate_update_pdf14trans(pgs, &params);
470
0
        if (code < 0)
471
0
            return(code);
472
980k
    } else {
473
980k
        if_debug0m('v', pgs->memory, "[v]gs_push_transparency_state NOT sending\n");
474
980k
    }
475
980k
    return(0);
476
980k
}
477
478
int
479
gs_pop_transparency_state(gs_gstate *pgs, bool force)
480
943k
{
481
943k
    gs_pdf14trans_params_t params = { 0 };
482
943k
    int code;
483
484
943k
    if (check_for_nontrans_pattern(pgs,
485
943k
                  (unsigned char *)"gs_pop_transparency_state")) {
486
2.78k
        return(0);
487
2.78k
    }
488
    /* Check if flag is set, which indicates that we have
489
       an active softmask for the graphic state.  We
490
       need to communicate to the compositor to pop
491
       the softmask */
492
940k
    if ( pgs->trans_flags.xstate_change || force) {
493
19.8k
        if_debug0m('v', pgs->memory, "[v]gs_pop_transparency_state sending\n");
494
19.8k
        params.pdf14_op = PDF14_POP_TRANS_STATE;
495
19.8k
        code = gs_gstate_update_pdf14trans(pgs, &params);
496
19.8k
        if ( code < 0 )
497
0
            return (code);
498
920k
    } else {
499
920k
        if_debug0m('v', pgs->memory, "[v]gs_pop_transparency_state NOT sending\n");
500
920k
    }
501
    /* There is no reason to reset any of the flags since
502
       they will be reset by the graphic state restore */
503
940k
    return(0);
504
940k
}
505
506
int
507
gx_pop_transparency_state(gs_gstate * pgs, gx_device * pdev)
508
2.42M
{
509
2.42M
    if_debug0m('v', pgs->memory, "[v]gx_pop_transparency_state\n");
510
2.42M
    return (*dev_proc(pdev, pop_transparency_state)) (pdev, pgs);
511
2.42M
}
512
513
int
514
gx_push_transparency_state(gs_gstate * pgs, gx_device * pdev)
515
0
{
516
0
    if_debug0m('v', pgs->memory, "[v]gx_push_transparency_state\n");
517
0
    return (*dev_proc(pdev, push_transparency_state)) (pdev, pgs);
518
0
}
519
520
/*
521
 * Handler for identity mask transfer functions.
522
 */
523
static int
524
mask_transfer_identity(double in, float *out, void *proc_data)
525
5.14M
{
526
5.14M
    *out = (float) in;
527
5.14M
    return 0;
528
5.14M
}
529
530
void
531
gs_trans_mask_params_init(gs_transparency_mask_params_t *ptmp,
532
                          gs_transparency_mask_subtype_t subtype)
533
49.8k
{
534
49.8k
    ptmp->ColorSpace = 0;
535
49.8k
    ptmp->subtype = subtype;
536
49.8k
    ptmp->Background_components = 0;
537
49.8k
    ptmp->Matte_components = 0;
538
49.8k
    ptmp->GrayBackground = 0.0;
539
49.8k
    ptmp->TransferFunction = mask_transfer_identity;
540
49.8k
    ptmp->TransferFunction_data = 0;
541
49.8k
    ptmp->replacing = false;
542
49.8k
    ptmp->iccprofile = NULL;
543
49.8k
}
544
545
int
546
gs_begin_transparency_mask(gs_gstate * pgs,
547
                           const gs_transparency_mask_params_t * ptmp,
548
                           const gs_rect * pbbox, bool mask_is_image)
549
47.7k
{
550
47.7k
    gs_pdf14trans_params_t params = { 0 };
551
47.7k
    gs_pdf14trans_params_t params_color = { 0 };
552
47.7k
    const int l = sizeof(params.Background[0]) * ptmp->Background_components;
553
47.7k
    const int m = sizeof(params.Matte[0]) * ptmp->Matte_components;
554
47.7k
    int i, code;
555
47.7k
    gs_color_space *blend_color_space;
556
47.7k
    gsicc_manager_t *icc_manager = pgs->icc_manager;
557
47.7k
    bool deep = device_is_deep(pgs->device);
558
559
47.7k
    if (check_for_nontrans_pattern(pgs,
560
47.7k
                  (unsigned char *)"gs_pop_transparency_state")) {
561
0
        return(0);
562
0
    }
563
47.7k
    params.pdf14_op = PDF14_BEGIN_TRANS_MASK;
564
47.7k
    params.bbox = *pbbox;
565
47.7k
    params.subtype = ptmp->subtype;
566
47.7k
    params.Background_components = ptmp->Background_components;
567
47.7k
    memcpy(params.Background, ptmp->Background, l);
568
47.7k
    params.ColorSpace = ptmp->ColorSpace;
569
47.7k
    params.Matte_components = ptmp->Matte_components;
570
47.7k
    memcpy(params.Matte, ptmp->Matte, m);
571
47.7k
    params.GrayBackground = ptmp->GrayBackground;
572
47.7k
    params.transfer_function = ptmp->TransferFunction_data;
573
47.7k
    params.function_is_identity =
574
47.7k
            (ptmp->TransferFunction == mask_transfer_identity);
575
47.7k
    params.mask_is_image = mask_is_image;
576
47.7k
    params.replacing = ptmp->replacing;
577
578
    /* The eventual state that we want this smask to be moved to
579
       is always gray.  This should provide us with a significant
580
       speed improvement over the old code.  This does not keep us
581
       from having groups within the softmask getting blended in different
582
       color spaces, it just makes the final space be gray, which is what
583
       we will need to get to eventually anyway. In this way we avoid a
584
       final color conversion on a potentially large buffer. */
585
    /* Also check if we have loaded in the transparency icc profiles.  If not
586
       go ahead and take care of that now */
587
47.7k
    if (icc_manager->smask_profiles == NULL) {
588
2.73k
        code = gsicc_initialize_iccsmask(icc_manager);
589
2.73k
        if (code < 0)
590
0
            return(code);
591
2.73k
    }
592
    /* A new soft mask group,  make sure the profiles are set */
593
47.7k
    if_debug0m('v', pgs->memory, "[v]pushing soft mask color sending\n");
594
47.7k
    if (params.subtype != TRANSPARENCY_MASK_None) {
595
20.4k
        params_color.pdf14_op = PDF14_PUSH_SMASK_COLOR;
596
20.4k
        code = gs_gstate_update_pdf14trans(pgs, &params_color);
597
20.4k
        if (code < 0)
598
0
            return(code);
599
20.4k
        blend_color_space = gs_cspace_new_DeviceGray(pgs->memory);
600
20.4k
        if (blend_color_space == NULL)
601
0
            return_error(gs_error_VMerror);
602
20.4k
        blend_color_space->cmm_icc_profile_data = pgs->icc_manager->default_gray;
603
20.4k
        gsicc_adjust_profile_rc(blend_color_space->cmm_icc_profile_data, 1, "gs_begin_transparency_mask");
604
20.4k
        if_debug9m('v', pgs->memory, "[v]("PRI_INTPTR")gs_begin_transparency_mask [%g %g %g %g]\n"
605
20.4k
                   "      subtype = %d  Background_components = %d, Matte_components = %d, %s\n",
606
20.4k
                  (intptr_t)pgs, pbbox->p.x, pbbox->p.y, pbbox->q.x, pbbox->q.y,
607
20.4k
                  (int)ptmp->subtype, ptmp->Background_components,
608
20.4k
                  ptmp->Matte_components,
609
20.4k
                  (ptmp->TransferFunction == mask_transfer_identity ? "no TR" :
610
20.4k
                   "has TR"));
611
        /* Sample the transfer function */
612
        /* For non-deep cases, we sample at 00,01,02..fe,ff.
613
         * For deep cases, we sample from 0000,0100,0200..fe00,ff00 and a final one at ffff.
614
         * This enables us to interpolate easily.
615
         */
616
20.4k
        if (deep) {
617
0
            uint16_t *trans16 = (uint16_t *)params.transfer_fn;
618
0
            float out;
619
0
            for (i = 0; i < MASK_TRANSFER_FUNCTION_SIZE; i++) {
620
0
                float in = (float)(i * (1.0 / MASK_TRANSFER_FUNCTION_SIZE));
621
622
0
                ptmp->TransferFunction(in, &out, ptmp->TransferFunction_data);
623
0
                trans16[i] = (uint16_t)floor((double)(out * 65535 + 0.5));
624
0
            }
625
0
            ptmp->TransferFunction(1.0, &out, ptmp->TransferFunction_data);
626
0
            trans16[MASK_TRANSFER_FUNCTION_SIZE] = (uint16_t)floor((double)(out * 65535 + 0.5));
627
20.4k
        } else {
628
5.24M
            for (i = 0; i < MASK_TRANSFER_FUNCTION_SIZE; i++) {
629
5.22M
                float in = (float)(i * (1.0 / (MASK_TRANSFER_FUNCTION_SIZE - 1)));
630
5.22M
                float out;
631
632
5.22M
                ptmp->TransferFunction(in, &out, ptmp->TransferFunction_data);
633
5.22M
                params.transfer_fn[i] = (byte)floor((double)(out * 255 + 0.5));
634
5.22M
            }
635
20.4k
        }
636
        /* Note:  This function is called during the c-list writer side. */
637
20.4k
        if ( blend_color_space->cmm_icc_profile_data != NULL ) {
638
        /* Blending space is ICC based.  If we are doing c-list rendering we will
639
           need to write this color space into the clist. */
640
20.4k
            params.group_color_type = ICC;
641
20.4k
            params.group_color_numcomps =
642
20.4k
                    blend_color_space->cmm_icc_profile_data->num_comps;
643
            /* Get the ICC profile */
644
            /* We don't reference count this - see comment in
645
             * pdf14_update_device_color_procs_pop_c()
646
             */
647
20.4k
            params.iccprofile = blend_color_space->cmm_icc_profile_data;
648
20.4k
            params.icc_hash = gsicc_get_hash(blend_color_space->cmm_icc_profile_data);
649
20.4k
        } else {
650
0
            params.group_color_type = GRAY_SCALE;
651
0
            params.group_color_numcomps = 1;  /* Need to check */
652
0
        }
653
        /* Explicitly decrement the profile data since blend_color_space may not
654
         * be an ICC color space object.
655
         */
656
20.4k
        gsicc_adjust_profile_rc(blend_color_space->cmm_icc_profile_data, -1, "gs_begin_transparency_mask");
657
20.4k
        rc_decrement_only_cs(blend_color_space, "gs_begin_transparency_mask");
658
20.4k
    }
659
47.7k
    return gs_gstate_update_pdf14trans(pgs, &params);
660
47.7k
}
661
662
/* This occurs on the c-list reader side */
663
664
int
665
gx_begin_transparency_mask(gs_gstate * pgs, gx_device * pdev,
666
                                const gs_pdf14trans_params_t * pparams)
667
3.56M
{
668
3.56M
    gx_transparency_mask_params_t tmp;
669
3.56M
    const int l = sizeof(pparams->Background[0]) * pparams->Background_components;
670
3.56M
    const int m = sizeof(pparams->Matte[0]) * pparams->Matte_components;
671
672
3.56M
    tmp.group_color_type = pparams->group_color_type;
673
3.56M
    tmp.subtype = pparams->subtype;
674
3.56M
    tmp.group_color_numcomps = pparams->group_color_numcomps;
675
3.56M
    tmp.Background_components = pparams->Background_components;
676
3.56M
    memcpy(tmp.Background, pparams->Background, l);
677
3.56M
    tmp.Matte_components = pparams->Matte_components;
678
3.56M
    memcpy(tmp.Matte, pparams->Matte, m);
679
3.56M
    tmp.GrayBackground = pparams->GrayBackground;
680
3.56M
    tmp.function_is_identity = pparams->function_is_identity;
681
3.56M
    tmp.idle = pparams->idle;
682
3.56M
    tmp.replacing = pparams->replacing;
683
3.56M
    tmp.mask_id = pparams->mask_id;
684
685
3.56M
    if (tmp.group_color_type == ICC ) {
686
        /* Do I need to ref count here? */
687
361k
        tmp.iccprofile = pparams->iccprofile;
688
361k
        tmp.icc_hashcode = pparams->icc_hash;
689
3.20M
    } else {
690
3.20M
        tmp.iccprofile = NULL;
691
3.20M
        tmp.icc_hashcode = 0;
692
3.20M
    }
693
3.56M
    memcpy(tmp.transfer_fn, pparams->transfer_fn, size_of(tmp.transfer_fn));
694
3.56M
    if_debug10m('v', pgs->memory,
695
3.56M
               "[v]("PRI_INTPTR")gx_begin_transparency_mask [%g %g %g %g]\n"
696
3.56M
               "      subtype = %d  Background_components = %d Matte_components = %d Num_grp_clr_comp = %d %s\n",
697
3.56M
              (intptr_t)pgs, pparams->bbox.p.x, pparams->bbox.p.y,
698
3.56M
              pparams->bbox.q.x, pparams->bbox.q.y,
699
3.56M
              (int)tmp.subtype, tmp.Background_components, tmp.Matte_components,
700
3.56M
              tmp.group_color_numcomps,
701
3.56M
              (tmp.function_is_identity ? "no TR" :
702
3.56M
               "has TR"));
703
3.56M
    return (*dev_proc(pdev, begin_transparency_mask))
704
3.56M
                        (pdev, &tmp, &(pparams->bbox), pgs, NULL);
705
3.56M
}
706
707
int
708
gs_end_transparency_mask(gs_gstate *pgs,
709
                         gs_transparency_channel_selector_t csel)
710
20.4k
{
711
20.4k
    gs_pdf14trans_params_t params = { 0 };
712
20.4k
    gs_pdf14trans_params_t params_color = { 0 };
713
20.4k
    int code;
714
715
20.4k
    if (check_for_nontrans_pattern(pgs,
716
20.4k
                  (unsigned char *)"gs_end_transparency_mask")) {
717
0
        return(0);
718
0
    }
719
    /* If we have done a q then set a flag to watch for any Qs */
720
   /* if (pgs->trans_flags.xstate_pending)
721
        pgs->trans_flags.xstate_change = true; */
722
    /* This should not depend upon if we have encountered a q
723
       operation.  We could be setting a softmask, before
724
       there is any q operation.  Unlikely but it could happen.
725
       Then if we encouter a q operation (and this flag
726
       is true) we will need to
727
       push the mask graphic state (PDF14_PUSH_TRANS_STATE). */
728
20.4k
    pgs->trans_flags.xstate_change = true;
729
20.4k
    if_debug1m('v', pgs->memory,
730
20.4k
               "[v]xstate_changed set true, gstate level is %d\n", pgs->level);
731
20.4k
    if_debug2m('v', pgs->memory,
732
20.4k
               "[v]("PRI_INTPTR")gs_end_transparency_mask(%d)\n", (intptr_t)pgs,
733
20.4k
               (int)csel);
734
20.4k
    params.pdf14_op = PDF14_END_TRANS_MASK;  /* Other parameters not used */
735
20.4k
    params.csel = csel;
736
    /* If this is the outer end then return us to our normal defaults */
737
20.4k
    if_debug0m('v', pgs->memory, "[v]popping soft mask color sending\n");
738
20.4k
    params_color.pdf14_op = PDF14_POP_SMASK_COLOR;
739
20.4k
    code = gs_gstate_update_pdf14trans(pgs, &params_color);
740
20.4k
    if (code < 0)
741
0
        return(code);
742
20.4k
    return gs_gstate_update_pdf14trans(pgs, &params);
743
20.4k
}
744
745
int
746
gx_end_transparency_mask(gs_gstate * pgs, gx_device * pdev,
747
                                const gs_pdf14trans_params_t * pparams)
748
361k
{
749
361k
    if_debug2m('v', pgs->memory,
750
361k
               "[v]("PRI_INTPTR")gx_end_transparency_mask(%d)\n", (intptr_t)pgs,
751
361k
               (int)pparams->csel);
752
361k
    return (*dev_proc(pdev, end_transparency_mask)) (pdev, pgs);
753
361k
}
754
755
/*
756
 * We really only care about the number of spot colors when we have
757
 * a device which supports spot colors.  With the other devices we use
758
 * the tint transform function for DeviceN and Separation color spaces
759
 * and convert spot colors into process colors.
760
 */
761
static int
762
get_num_pdf14_spot_colors(gs_gstate * pgs)
763
18.5k
{
764
18.5k
    gx_device * dev = pgs->device;
765
18.5k
    gs_devn_params * pclist_devn_params = dev_proc(dev, ret_devn_params)(dev);
766
767
    /*
768
     * Devices which support spot colors store the PageSpotColors device
769
     * parameter inside their devn_params structure.  (This is done by the
770
     * devn_put_params routine.)  The PageSpotColors device parameter is
771
     * set by pdf_main whenever a PDF page is being processed.  See
772
     * countspotcolors in lib/pdf_main.ps.
773
     */
774
18.5k
    if (pclist_devn_params != NULL) {
775
        /* If the sep order names were specified, then we should only allocate
776
           for those.  But only the nonstandard colorants that are stored
777
           in num_separations.  See devn_put_params for details on this.
778
           Right now, the PDF14 device will always include CMYK.  A future
779
           optimization is to be able to NOT have those included in the buffer
780
           allocations if we don't specify them.  It would then be possible to
781
           output 8 separations at a time without using compressed color. */
782
5.83k
        if (pclist_devn_params->num_separation_order_names == 0) {
783
5.83k
            return pclist_devn_params->page_spot_colors;
784
5.83k
        }
785
0
        return (pclist_devn_params->separations.num_separations);
786
5.83k
    }
787
12.7k
    return 0;
788
18.5k
}
789
790
int
791
gs_push_pdf14trans_device(gs_gstate * pgs, bool is_pattern, bool retain,
792
                          int depth, int spot_color_count)
793
18.5k
{
794
18.5k
    gs_pdf14trans_params_t params = { 0 };
795
18.5k
    cmm_profile_t *icc_profile;
796
18.5k
    gsicc_rendering_param_t render_cond;
797
18.5k
    int code;
798
18.5k
    cmm_dev_profile_t *dev_profile;
799
18.5k
    unsigned char pattern_opsim_setting[2];
800
801
18.5k
    code = dev_proc(pgs->device, get_profile)(pgs->device,  &dev_profile);
802
18.5k
    if (code < 0)
803
0
        return code;
804
18.5k
    gsicc_extract_profile(GS_UNKNOWN_TAG, dev_profile, &icc_profile,
805
18.5k
                          &render_cond);
806
18.5k
    params.pdf14_op = PDF14_PUSH_DEVICE;
807
    /*
808
     * We really only care about the number of spot colors when we have
809
     * a device which supports spot colors.  With the other devices we use
810
     * the tint transform function for DeviceN and Separation color spaces
811
     * and convert spot colors into process colors.
812
     */
813
18.5k
    params.num_spot_colors = get_num_pdf14_spot_colors(pgs);
814
18.5k
    params.is_pattern = is_pattern;
815
816
    /* If pattern, get overprint simulation information from
817
       the pattern accumulators target device */
818
18.5k
    if (is_pattern && dev_proc(pgs->device, dev_spec_op)(pgs->device, gxdso_overprintsim_state, &pattern_opsim_setting, sizeof(pattern_opsim_setting))) {
819
        /* Use the target device setting */
820
4.69k
        params.overprint_sim_push = pattern_opsim_setting[0];
821
4.69k
        params.num_spot_colors_int = pattern_opsim_setting[1];
822
13.8k
    } else {
823
        /* Use information from interpreter */
824
13.8k
        params.num_spot_colors_int = spot_color_count;
825
13.8k
        if (depth < 0)
826
0
            params.overprint_sim_push = true;
827
13.8k
    }
828
829
    /* If we have an NCLR ICC profile, the extra spot colorants do
830
    *  get included in the transparency buffers. Trying to avoid
831
    * including them became a rube goldberg mess in terms of knowing
832
    * which colorants are on the page vs what has been specified and
833
    * any aliasing between these two.  Just too many things to go wrong.
834
    * So we allocate all and carry around. If you are doing special
835
    * spot handling with transparency this is the cost. */
836
837
18.5k
    if (dev_profile->spotnames != NULL && dev_profile->spotnames->count > 4) {
838
        /* Making an assumption here, that list is CMYK + extra.
839
           An error should have been thrown by the target device if not. */
840
0
        int has_tags = device_encodes_tags(pgs->device);
841
0
        int avail_page_spots = pgs->device->color_info.num_components - 4 - has_tags;
842
0
        params.num_spot_colors_int = avail_page_spots;
843
0
        params.num_spot_colors = avail_page_spots;
844
845
        /* This should not be possible, but lets be safe. We can't have a negative
846
          number of source spots to carry forward, so apply threshold. */
847
0
        if (params.num_spot_colors_int < 0)
848
0
            params.num_spot_colors_int = 0;
849
0
        if (params.num_spot_colors < 0)
850
0
            params.num_spot_colors = 0;
851
0
    }
852
853
    /* If we happen to be in a situation where we are going out to a device
854
       whose profile is CIELAB then we will need to make sure that we
855
       do our blending in RGB and convert to CIELAB when we do the put_image
856
       command */
857
18.5k
    if (icc_profile->data_cs == gsCIELAB ||
858
18.5k
        icc_profile->islab) {
859
0
        params.iccprofile = pgs->icc_manager->default_rgb;
860
0
    }
861
    /* Note: Other parameters not used */
862
18.5k
    return gs_gstate_update_pdf14trans2(pgs, &params, retain);
863
18.5k
}
864
865
int
866
gs_pop_pdf14trans_device(gs_gstate * pgs, bool is_pattern)
867
11.0k
{
868
11.0k
    gs_pdf14trans_params_t params = { 0 };
869
870
11.0k
    params.is_pattern = is_pattern;
871
11.0k
    params.pdf14_op = PDF14_POP_DEVICE;  /* Other parameters not used */
872
11.0k
    return gs_gstate_update_pdf14trans(pgs, &params);
873
11.0k
}
874
875
int
876
gs_abort_pdf14trans_device(gs_gstate * pgs)
877
0
{
878
0
    gs_pdf14trans_params_t params = { 0 };
879
880
0
    params.pdf14_op = PDF14_ABORT_DEVICE;  /* Other parameters not used */
881
0
    return gs_gstate_update_pdf14trans(pgs, &params);
882
0
}
883
884
/* Something has gone wrong have the device clean up everything */
885
886
int
887
gx_abort_trans_device(gs_gstate * pgs, gx_device * pdev)
888
0
{
889
0
    if_debug1m('v', pgs->memory, "[v]("PRI_INTPTR")gx_abort_trans_device\n", (intptr_t)pgs);
890
0
    return (*dev_proc(pdev, discard_transparency_layer)) (pdev, pgs);
891
0
}
892
893
int gs_setstrokeconstantalpha(gs_gstate *pgs, float alpha)
894
2.11M
{
895
2.11M
    pgs->strokeconstantalpha = alpha;
896
2.11M
    return 0;
897
2.11M
}
898
899
float gs_getstrokeconstantalpha(const gs_gstate *pgs)
900
25.1k
{
901
25.1k
    return pgs->strokeconstantalpha;
902
25.1k
}
903
904
int gs_setfillconstantalpha(gs_gstate *pgs, float alpha)
905
2.15M
{
906
2.15M
    pgs->fillconstantalpha = (float)alpha;
907
2.15M
    return 0;
908
2.15M
}
909
910
float gs_getfillconstantalpha(const gs_gstate *pgs)
911
81.3k
{
912
81.3k
    return pgs->fillconstantalpha;
913
81.3k
}
914
915
int gs_setalphaisshape(gs_gstate *pgs, bool AIS)
916
1.95M
{
917
1.95M
    pgs->alphaisshape = AIS;
918
1.95M
    return 0;
919
1.95M
}
920
921
bool gs_getalphaisshape(gs_gstate *pgs)
922
947k
{
923
947k
    return pgs->alphaisshape;
924
947k
}