Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/base/gsicc_blacktext.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2023 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
/*  Handling of color spaces stored during replacement of all
17
 *  text with black.
18
*/
19
20
#include "gsmemory.h"
21
#include "gsstruct.h"
22
#include "gzstate.h"
23
#include "gsicc_blacktext.h"
24
#include "gsicc_cache.h"
25
26
/* gsicc_blacktextvec_state_t is going to be storing GCed items
27
   (color spaces and client colors) and so will need to be GCed */
28
gs_private_st_ptrs4(st_blacktextvec_state, gsicc_blacktextvec_state_t,
29
    "gsicc_blacktextvec_state", blacktextvec_state_enum_ptrs,
30
    blacktextvec_state_reloc_ptrs, pcs, pcs_alt, pcc, pcc_alt);
31
32
static void
33
rc_gsicc_blacktextvec_state_free(gs_memory_t *mem, void *ptr_in,
34
    client_name_t cname)
35
0
{
36
0
    gsicc_blacktextvec_state_t *state = (gsicc_blacktextvec_state_t*)ptr_in;
37
38
0
    rc_decrement_cs(state->pcs, "rc_gsicc_blacktextvec_state_free");
39
0
    rc_decrement_cs(state->pcs_alt, "rc_gsicc_blacktextvec_state_free");
40
41
0
    gs_free_object(state->memory, state,
42
0
        "rc_gsicc_blacktextvec_state_free");
43
0
}
44
45
gsicc_blacktextvec_state_t*
46
gsicc_blacktextvec_state_new(gs_memory_t *memory, bool is_text)
47
0
{
48
0
    gsicc_blacktextvec_state_t *result;
49
50
0
    result = gs_alloc_struct(memory->stable_memory, gsicc_blacktextvec_state_t,
51
0
        &st_blacktextvec_state, "gsicc_blacktextvec_state_new");
52
0
    if (result == NULL)
53
0
        return NULL;
54
0
    rc_init_free(result, memory->stable_memory, 1, rc_gsicc_blacktextvec_state_free);
55
0
    result->memory = memory->stable_memory;
56
0
    result->pcs = NULL;
57
0
    result->pcs_alt = NULL;
58
0
    result->pcc = NULL;
59
0
    result->pcc_alt = NULL;
60
0
    result->is_text = is_text;
61
62
0
    return result;
63
0
}
64
65
/* Crude white color check. Only valid for ICC based RGB, CMYK, Gray, and LAB CS.
66
  Makes some assumptions about profile.  Also may want some tolerance check. */
67
bool gsicc_is_white_blacktextvec(gs_gstate *pgs, gx_device *dev, gs_color_space* pcs, gs_client_color* pcc)
68
0
{
69
0
    double Lstar = 0;
70
0
    double astar = 0;
71
0
    double bstar = 0;
72
0
    cmm_dev_profile_t* dev_profile;
73
74
0
    dev_proc(dev, get_profile)(dev, &dev_profile);
75
76
0
    if (gs_color_space_get_index(pcs) == gs_color_space_index_ICC) {
77
0
        if (pcs->cmm_icc_profile_data->data_cs == gsCIELAB) {
78
0
            if (pcc->paint.values[0] >= dev_profile->blackthresholdL &&
79
0
                fabs(pcc->paint.values[1]) < dev_profile->blackthresholdC &&
80
0
                fabs(pcc->paint.values[2]) < dev_profile->blackthresholdC)
81
0
                    return true;
82
0
            else
83
0
                return false;
84
0
        }
85
        /* For all others, lets get to CIELAB value */
86
0
        if (pgs->icc_manager->lab_profile != NULL) {
87
0
            gsicc_link_t *icc_link;
88
0
            gsicc_rendering_param_t rendering_params;
89
0
            unsigned short psrc[4];
90
0
            unsigned short pdes[3];
91
92
0
            rendering_params.black_point_comp = gsBLACKPTCOMP_ON;
93
0
            rendering_params.graphics_type_tag = GS_UNKNOWN_TAG;
94
0
            rendering_params.override_icc = false;
95
0
            rendering_params.preserve_black = gsBKPRESNOTSPECIFIED;
96
0
            rendering_params.rendering_intent = gsRELATIVECOLORIMETRIC;
97
0
            rendering_params.cmm = gsCMM_DEFAULT;
98
99
0
            icc_link = gsicc_get_link_profile(pgs, NULL, pcs->cmm_icc_profile_data,
100
0
                                          pgs->icc_manager->lab_profile, &rendering_params,
101
0
                                          pgs->memory, false);
102
0
            if (icc_link == NULL)
103
0
                return false;
104
105
0
            switch (pcs->cmm_icc_profile_data->data_cs) {
106
0
                case gsGRAY:
107
0
                    psrc[0] = (unsigned short)(pcc->paint.values[0] * 65535);
108
0
                    break;
109
0
                case gsRGB:
110
0
                    psrc[0] = (unsigned short)(pcc->paint.values[0] * 65535);
111
0
                    psrc[1] = (unsigned short)(pcc->paint.values[1] * 65535);
112
0
                    psrc[2] = (unsigned short)(pcc->paint.values[2] * 65535);
113
0
                    break;
114
0
                case gsCMYK:
115
0
                    psrc[0] = (unsigned short)(pcc->paint.values[0] * 65535);
116
0
                    psrc[1] = (unsigned short)(pcc->paint.values[1] * 65535);
117
0
                    psrc[2] = (unsigned short)(pcc->paint.values[2] * 65535);
118
0
                    psrc[3] = (unsigned short)(pcc->paint.values[3] * 65535);
119
0
                    break;
120
0
                default:
121
0
                    gsicc_release_link(icc_link);
122
0
                    return false;
123
0
            }
124
0
            (icc_link->procs.map_color)(NULL, icc_link, psrc, pdes, 2);
125
0
            gsicc_release_link(icc_link);
126
127
0
            Lstar = pdes[0] * 100.0 / 65535.0;
128
0
            astar = pdes[1] * 256.0 / 65535.0 - 128.0;
129
0
            bstar = pdes[2] * 256.0 / 65535.0 - 128.0;
130
131
0
            if (Lstar >= dev_profile->blackthresholdL &&
132
0
                fabs(astar) < dev_profile->blackthresholdC &&
133
0
                fabs(bstar) < dev_profile->blackthresholdC)
134
0
                return true;
135
0
            else
136
0
                return false;
137
0
        } else {
138
            /* Something to fall back on */
139
0
            switch (pcs->cmm_icc_profile_data->data_cs) {
140
0
                case gsGRAY:
141
0
                    if (pcc->paint.values[0] == 1.0)
142
0
                        return true;
143
0
                    else
144
0
                        return false;
145
0
                    break;
146
0
                case gsRGB:
147
0
                    if (pcc->paint.values[0] == 1.0 && pcc->paint.values[1] == 1.0 &&
148
0
                        pcc->paint.values[2] == 1.0)
149
0
                        return true;
150
0
                    else
151
0
                        return false;
152
0
                    break;
153
0
                case gsCMYK:
154
0
                    if (pcc->paint.values[0] == 0.0 && pcc->paint.values[1] == 0.0 &&
155
0
                        pcc->paint.values[2] == 0.0 && pcc->paint.values[3] == 0.0)
156
0
                        return true;
157
0
                    else
158
0
                        return false;
159
0
                    break;
160
0
                default:
161
0
                    return false;
162
0
            }
163
0
        }
164
0
    } else
165
0
        return false;
166
0
}
167
168
bool gsicc_setup_blacktextvec(gs_gstate *pgs, gx_device *dev, bool is_text)
169
0
{
170
0
    gs_color_space *pcs_curr = gs_currentcolorspace_inline(pgs);
171
0
    gs_color_space *pcs_alt = gs_swappedcolorspace_inline(pgs);
172
173
    /* If neither space is ICC then we are not doing anything */
174
0
    if (!gs_color_space_is_ICC(pcs_curr) && !gs_color_space_is_ICC(pcs_alt))
175
0
        return false;
176
177
    /* Create a new object to hold the cs details */
178
0
    pgs->black_textvec_state = gsicc_blacktextvec_state_new(pgs->memory, is_text);
179
0
    if (pgs->black_textvec_state == NULL)
180
0
        return false; /* No error just move on */
181
182
    /* If curr space is ICC then store it */
183
0
    if  (gs_color_space_is_ICC(pcs_curr)) {
184
0
        rc_increment_cs(pcs_curr);  /* We are storing the cs. Will decrement when structure is released */
185
0
        pgs->black_textvec_state->pcs = pcs_curr;
186
0
        pgs->black_textvec_state->pcc = pgs->color[0].ccolor;
187
0
        cs_adjust_color_count(pgs, 1); /* The set_gray will do a decrement, only need if pattern */
188
0
        pgs->black_textvec_state->value[0] = pgs->color[0].ccolor->paint.values[0];
189
190
0
        if (gsicc_is_white_blacktextvec(pgs, dev, pcs_curr, pgs->color[0].ccolor))
191
0
            gs_setgray(pgs, 1.0);
192
0
        else
193
0
            gs_setgray(pgs, 0.0);
194
0
    }
195
196
    /* If alt space is ICC then store it */
197
0
    if (gs_color_space_is_ICC(pcs_alt)) {
198
0
        rc_increment_cs(pcs_alt);  /* We are storing the cs. Will decrement when structure is released */
199
0
        pgs->black_textvec_state->pcs_alt = pcs_alt;
200
201
0
        gs_swapcolors_quick(pgs);  /* Have to swap for set_gray and adjust color count */
202
0
        pgs->black_textvec_state->pcc_alt = pgs->color[0].ccolor;
203
0
        cs_adjust_color_count(pgs, 1); /* The set_gray will do a decrement, only need if pattern */
204
0
        pgs->black_textvec_state->value[1] = pgs->color[0].ccolor->paint.values[0];
205
206
0
        if (gsicc_is_white_blacktextvec(pgs, dev, pcs_alt, pgs->color[0].ccolor))
207
0
            gs_setgray(pgs, 1.0);
208
0
        else
209
0
            gs_setgray(pgs, 0.0);
210
0
        gs_swapcolors_quick(pgs);
211
0
    }
212
213
0
    pgs->black_textvec_state->is_fill = pgs->is_fill_color;
214
0
    return true; /* Need to clean up */
215
0
}
216
217
void
218
gsicc_restore_blacktextvec(gs_gstate *pgs, bool is_text)
219
0
{
220
0
    gsicc_blacktextvec_state_t *state = pgs->black_textvec_state;
221
0
    int code;
222
223
0
    if (state == NULL)
224
0
        return;
225
226
0
    if (is_text != state->is_text)
227
0
        return;
228
229
    /* Make sure state and original are same fill_color condition */
230
0
    if (state->rc.ref_count == 1) {
231
0
        if ((state->is_fill && pgs->is_fill_color) || (!state->is_fill && !pgs->is_fill_color)) {
232
0
            if (pgs->black_textvec_state->pcs != NULL) {
233
0
                if ((code = gs_setcolorspace_only(pgs, pgs->black_textvec_state->pcs)) >= 0) {
234
                    /* current client color is gray.  no need to decrement */
235
0
                    pgs->color[0].ccolor = pgs->black_textvec_state->pcc;
236
0
                    pgs->color[0].ccolor->paint.values[0] = pgs->black_textvec_state->value[0];
237
0
                }
238
0
                gx_unset_dev_color(pgs);
239
0
            }
240
0
            if (pgs->black_textvec_state->pcs_alt != NULL) {
241
0
                gs_swapcolors_quick(pgs);
242
0
                if ((code = gs_setcolorspace_only(pgs, pgs->black_textvec_state->pcs_alt)) >= 0) {
243
0
                    pgs->color[0].ccolor = pgs->black_textvec_state->pcc_alt;
244
0
                    pgs->color[0].ccolor->paint.values[0] = pgs->black_textvec_state->value[1];
245
0
                }
246
0
                gs_swapcolors_quick(pgs);
247
0
                gx_unset_alt_dev_color(pgs);
248
0
            }
249
0
        } else {
250
0
            if (pgs->black_textvec_state->pcs_alt != NULL) {
251
0
                if ((code = gs_setcolorspace_only(pgs, pgs->black_textvec_state->pcs_alt)) >= 0) {
252
0
                    pgs->color[0].ccolor = pgs->black_textvec_state->pcc_alt;
253
0
                    pgs->color[0].ccolor->paint.values[0] = pgs->black_textvec_state->value[1];
254
0
                }
255
0
                gx_unset_dev_color(pgs);
256
0
            }
257
0
            if (pgs->black_textvec_state->pcs != NULL) {
258
0
                gs_swapcolors_quick(pgs);
259
0
                if ((code = gs_setcolorspace_only(pgs, pgs->black_textvec_state->pcs)) >= 0) {
260
0
                    pgs->color[0].ccolor = pgs->black_textvec_state->pcc;
261
0
                    pgs->color[0].ccolor->paint.values[0] = pgs->black_textvec_state->value[0];
262
0
                }
263
0
                gs_swapcolors_quick(pgs);
264
0
                gx_unset_alt_dev_color(pgs);
265
0
            }
266
0
        }
267
0
    }
268
0
    rc_decrement(state, "gsicc_restore_black_text");
269
0
    pgs->black_textvec_state = NULL;
270
0
}