Coverage Report

Created: 2025-06-10 07:06

/src/ghostpdl/base/gxdevndi.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
17
#include "gx.h"
18
#include "gsstruct.h"
19
#include "gsdcolor.h"
20
#include "gxdevice.h"
21
#include "gxlum.h"
22
#include "gxcmap.h"
23
#include "gxdither.h"
24
#include "gzht.h"
25
#include "gxfrac.h"
26
27
/*
28
 * Binary halftoning algorithms.
29
 *
30
 * The procedures in this file use halftoning (if necessary)
31
 * to implement a given device color that has already gone through
32
 * the transfer function.  There are two major cases: gray and color.
33
 * Gray halftoning always uses a binary screen.  Color halftoning
34
 * uses either a fast algorithm with a binary screen that produces
35
 * relatively poor approximations, or a very slow algorithm with a
36
 * general colored screen (or screens) that faithfully implements
37
 * the Adobe specifications.
38
 */
39
40
/* Tables for fast computation of fractional color levels. */
41
/* We have to put the table before any uses of it because of a bug */
42
/* in the VAX C compiler. */
43
/* We have to split up the definition of the table itself because of a bug */
44
/*  in the IBM AIX 3.2 C compiler. */
45
static const gx_color_value q0[] = {
46
    0
47
};
48
static const gx_color_value q1[] = {
49
    0, frac_color_(1, 1)
50
};
51
static const gx_color_value q2[] = {
52
    0, frac_color_(1, 2), frac_color_(2, 2)
53
};
54
static const gx_color_value q3[] = {
55
    0, frac_color_(1, 3), frac_color_(2, 3), frac_color_(3, 3)
56
};
57
static const gx_color_value q4[] = {
58
    0, frac_color_(1, 4), frac_color_(2, 4), frac_color_(3, 4),
59
    frac_color_(4, 4)
60
};
61
static const gx_color_value q5[] = {
62
    0, frac_color_(1, 5), frac_color_(2, 5), frac_color_(3, 5),
63
    frac_color_(4, 5), frac_color_(5, 5)
64
};
65
static const gx_color_value q6[] = {
66
    0, frac_color_(1, 6), frac_color_(2, 6), frac_color_(3, 6),
67
    frac_color_(4, 6), frac_color_(5, 6), frac_color_(6, 6)
68
};
69
static const gx_color_value q7[] = {
70
    0, frac_color_(1, 7), frac_color_(2, 7), frac_color_(3, 7),
71
    frac_color_(4, 7), frac_color_(5, 7), frac_color_(6, 7), frac_color_(7, 7)
72
};
73
74
/* We export fc_color_quo for the fractional_color macro in gzht.h. */
75
const gx_color_value *const fc_color_quo[8] = {
76
    q0, q1, q2, q3, q4, q5, q6, q7
77
};
78
79
/*
80
 * Render DeviceN possibly by halftoning.
81
 *  pcolors = pointer to an array color values (as fracs)
82
 *  pdevc - pointer to device color structure
83
 *  dev = pointer to device data structure
84
 *  pht = pointer to halftone data structure
85
 *  ht_phase  = halftone phase
86
 *  gray_colorspace = true -> current color space is DeviceGray.
87
 *  This is part of a kludge to minimize differences in the
88
 *  regression testing.
89
 */
90
int
91
gx_render_device_DeviceN(frac * pcolor,
92
        gx_device_color * pdevc, gx_device * dev,
93
        gx_device_halftone * pdht, const gs_int_point * ht_phase)
94
29.2k
{
95
29.2k
    uint max_value[GS_CLIENT_COLOR_MAX_COMPONENTS];
96
29.2k
    frac dither_check = 0;
97
29.2k
    uint int_color[GS_CLIENT_COLOR_MAX_COMPONENTS];
98
29.2k
    gx_color_value vcolor[GS_CLIENT_COLOR_MAX_COMPONENTS];
99
29.2k
    int i;
100
29.2k
    int num_colors = dev->color_info.num_components;
101
29.2k
    uint l_color[GS_CLIENT_COLOR_MAX_COMPONENTS];
102
103
58.4k
    for (i=0; i<num_colors; i++) {
104
29.2k
        max_value[i] = (dev->color_info.gray_index == i) ?
105
29.2k
             dev->color_info.dither_grays - 1 :
106
29.2k
             dev->color_info.dither_colors - 1;
107
29.2k
    }
108
109
58.4k
    for (i = 0; i < num_colors; i++) {
110
29.2k
        unsigned long hsize = pdht && i <= pdht->num_comp ?
111
9
                (unsigned) pdht->components[i].corder.num_levels
112
29.2k
                : 1;
113
29.2k
        unsigned long nshades = hsize * max_value[i] + 1;
114
29.2k
        long shade = pcolor[i] * nshades / (frac_1_long + 1);
115
29.2k
        int_color[i] = shade / hsize;
116
29.2k
        l_color[i] = shade % hsize;
117
29.2k
        if (max_value[i] < MIN_CONTONE_LEVELS)
118
29.2k
            dither_check |= l_color[i];
119
29.2k
    }
120
121
#ifdef DEBUG
122
    if (gs_debug_c('c')) {
123
        dmlprintf1(dev->memory, "[c]ncomp=%d ", num_colors);
124
        for (i = 0; i < num_colors; i++)
125
            dmlprintf1(dev->memory, "0x%x, ", pcolor[i]);
126
        dmlprintf(dev->memory, "-->   ");
127
        for (i = 0; i < num_colors; i++)
128
            dmlprintf2(dev->memory, "%x+0x%x, ", int_color[i], l_color[i]);
129
        dmlprintf(dev->memory, "\n");
130
    }
131
#endif
132
133
    /* Check for no dithering required */
134
29.2k
    if (!dither_check) {
135
58.4k
        for (i = 0; i < num_colors; i++)
136
29.2k
            vcolor[i] = fractional_color(int_color[i], max_value[i]);
137
29.2k
        color_set_pure(pdevc, dev_proc(dev, encode_color)(dev, vcolor));
138
29.2k
        return 0;
139
29.2k
    }
140
141
    /* Use the slow, general colored halftone algorithm. */
142
143
0
    for (i = 0; i < num_colors; i++)
144
0
        _color_set_c(pdevc, i, int_color[i], l_color[i]);
145
0
    gx_complete_halftone(pdevc, num_colors, pdht);
146
147
0
    if (pdht)
148
0
        color_set_phase_mod(pdevc, ht_phase->x, ht_phase->y,
149
0
                            pdht->lcm_width, pdht->lcm_height);
150
151
    /* Determine if we are using only one component */
152
0
    if (!(pdevc->colors.colored.plane_mask &
153
0
         (pdevc->colors.colored.plane_mask - 1))) {
154
        /* We can reduce this color to a binary halftone or pure color. */
155
0
        return gx_devn_reduce_colored_halftone(pdevc, dev);
156
0
    }
157
158
0
    return 1;
159
0
}
160
161
/* Reduce a colored halftone to a binary halftone or pure color. */
162
/* This routine is called when only one component is being halftoned. */
163
int
164
gx_devn_reduce_colored_halftone(gx_device_color *pdevc, gx_device *dev)
165
0
{
166
0
    int planes = pdevc->colors.colored.plane_mask;
167
0
    int num_colors = dev->color_info.num_components;
168
0
    uint max_value[GS_CLIENT_COLOR_MAX_COMPONENTS];
169
0
    uint b[GX_DEVICE_COLOR_MAX_COMPONENTS];
170
0
    gx_color_value v[GX_DEVICE_COLOR_MAX_COMPONENTS];
171
0
    gx_color_index c0, c1;
172
0
    int i;
173
174
0
    for (i = 0; i < num_colors; i++) {
175
0
        max_value[i] = (dev->color_info.gray_index == i) ?
176
0
             dev->color_info.dither_grays - 1 :
177
0
             dev->color_info.dither_colors - 1;
178
0
        b[i] = pdevc->colors.colored.c_base[i];
179
0
        v[i] = fractional_color(b[i], max_value[i]);
180
0
    }
181
0
    c0 = dev_proc(dev, encode_color)(dev, v);
182
183
0
    if (planes == 0) {
184
        /*
185
         * Use a pure color.  This case is unlikely, but it can occur if
186
         * (and only if) the difference of each component from the nearest
187
         * device color is less than one halftone level.
188
         */
189
0
        color_set_pure(pdevc, c0);
190
0
        return 0;
191
0
    } else {
192
        /* Use a binary color. */
193
0
        int i = 0;
194
0
        uint bi;
195
0
        const gx_device_halftone *pdht = pdevc->colors.colored.c_ht;
196
        /*
197
         * NB: the halftone orders are all set up for an additive color
198
         *     space.  To use these work with a subtractive color space, it is
199
         *     necessary to invert both the color level and the color
200
         *     pair. Note that if the original color was provided an
201
         *     additive space, this will reverse (in an approximate sense)
202
         *     the color conversion performed to express the color in
203
         *     subtractive space.
204
         */
205
0
        bool invert = dev->color_info.polarity == GX_CINFO_POLARITY_SUBTRACTIVE;
206
0
        uint level;
207
208
        /* Convert plane mask bit position to component number */
209
        /* Determine i = log2(planes);  This works for powers of two */
210
0
        while (planes > 7) {
211
0
            i += 3;
212
0
            planes >>= 3;
213
0
        }
214
0
        i += planes >> 1;  /* log2 for 1,2,4 */
215
216
0
        bi = b[i] + 1;
217
0
        v[i] = fractional_color(bi, max_value[i]);
218
0
        level = pdevc->colors.colored.c_level[i];
219
0
        c1 = dev_proc(dev, encode_color)(dev, v);
220
0
        if (invert) {
221
0
            level = pdht->components[i].corder.num_levels - level;
222
0
            color_set_binary_halftone_component(pdevc, pdht, i, c1, c0, level);
223
0
        } else
224
0
            color_set_binary_halftone_component(pdevc, pdht, i, c0, c1, level);
225
226
0
        return 1;
227
0
    }
228
0
}