/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 | 319M | { |
95 | 319M | uint max_value[GS_CLIENT_COLOR_MAX_COMPONENTS]; |
96 | 319M | frac dither_check = 0; |
97 | 319M | uint int_color[GS_CLIENT_COLOR_MAX_COMPONENTS]; |
98 | 319M | gx_color_value vcolor[GS_CLIENT_COLOR_MAX_COMPONENTS]; |
99 | 319M | int i; |
100 | 319M | int num_colors = dev->color_info.num_components; |
101 | 319M | uint l_color[GS_CLIENT_COLOR_MAX_COMPONENTS]; |
102 | | |
103 | 1.27G | for (i=0; i<num_colors; i++) { |
104 | 957M | max_value[i] = (dev->color_info.gray_index == i) ? |
105 | 67.2M | dev->color_info.dither_grays - 1 : |
106 | 957M | dev->color_info.dither_colors - 1; |
107 | 957M | } |
108 | | |
109 | 1.27G | for (i = 0; i < num_colors; i++) { |
110 | 957M | unsigned long hsize = pdht && i <= pdht->num_comp ? |
111 | 956M | (unsigned) pdht->components[i].corder.num_levels |
112 | 957M | : 1; |
113 | 957M | unsigned long nshades = hsize * max_value[i] + 1; |
114 | 957M | long shade = pcolor[i] * nshades / (frac_1_long + 1); |
115 | 957M | int_color[i] = shade / hsize; |
116 | 957M | l_color[i] = shade % hsize; |
117 | 957M | if (max_value[i] < MIN_CONTONE_LEVELS) |
118 | 957M | dither_check |= l_color[i]; |
119 | 957M | } |
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 | 319M | if (!dither_check) { |
135 | 567M | for (i = 0; i < num_colors; i++) |
136 | 429M | vcolor[i] = fractional_color(int_color[i], max_value[i]); |
137 | 137M | color_set_pure(pdevc, dev_proc(dev, encode_color)(dev, vcolor)); |
138 | 137M | return 0; |
139 | 137M | } |
140 | | |
141 | | /* Use the slow, general colored halftone algorithm. */ |
142 | | |
143 | 710M | for (i = 0; i < num_colors; i++) |
144 | 527M | _color_set_c(pdevc, i, int_color[i], l_color[i]); |
145 | 182M | gx_complete_halftone(pdevc, num_colors, pdht); |
146 | | |
147 | 182M | if (pdht) |
148 | 182M | color_set_phase_mod(pdevc, ht_phase->x, ht_phase->y, |
149 | 182M | pdht->lcm_width, pdht->lcm_height); |
150 | | |
151 | | /* Determine if we are using only one component */ |
152 | 182M | if (!(pdevc->colors.colored.plane_mask & |
153 | 182M | (pdevc->colors.colored.plane_mask - 1))) { |
154 | | /* We can reduce this color to a binary halftone or pure color. */ |
155 | 44.9M | return gx_devn_reduce_colored_halftone(pdevc, dev); |
156 | 44.9M | } |
157 | | |
158 | 137M | return 1; |
159 | 182M | } |
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 | 44.9M | { |
166 | 44.9M | int planes = pdevc->colors.colored.plane_mask; |
167 | 44.9M | int num_colors = dev->color_info.num_components; |
168 | 44.9M | uint max_value[GS_CLIENT_COLOR_MAX_COMPONENTS]; |
169 | 44.9M | uint b[GX_DEVICE_COLOR_MAX_COMPONENTS]; |
170 | 44.9M | gx_color_value v[GX_DEVICE_COLOR_MAX_COMPONENTS]; |
171 | 44.9M | gx_color_index c0, c1; |
172 | 44.9M | int i; |
173 | | |
174 | 145M | for (i = 0; i < num_colors; i++) { |
175 | 100M | max_value[i] = (dev->color_info.gray_index == i) ? |
176 | 25.4M | dev->color_info.dither_grays - 1 : |
177 | 100M | dev->color_info.dither_colors - 1; |
178 | 100M | b[i] = pdevc->colors.colored.c_base[i]; |
179 | 100M | v[i] = fractional_color(b[i], max_value[i]); |
180 | 100M | } |
181 | 44.9M | c0 = dev_proc(dev, encode_color)(dev, v); |
182 | | |
183 | 44.9M | 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 | 44.9M | } else { |
192 | | /* Use a binary color. */ |
193 | 44.9M | int i = 0; |
194 | 44.9M | uint bi; |
195 | 44.9M | 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 | 44.9M | bool invert = dev->color_info.polarity == GX_CINFO_POLARITY_SUBTRACTIVE; |
206 | 44.9M | uint level; |
207 | | |
208 | | /* Convert plane mask bit position to component number */ |
209 | | /* Determine i = log2(planes); This works for powers of two */ |
210 | 45.7M | while (planes > 7) { |
211 | 815k | i += 3; |
212 | 815k | planes >>= 3; |
213 | 815k | } |
214 | 44.9M | i += planes >> 1; /* log2 for 1,2,4 */ |
215 | | |
216 | 44.9M | bi = b[i] + 1; |
217 | 44.9M | v[i] = fractional_color(bi, max_value[i]); |
218 | 44.9M | level = pdevc->colors.colored.c_level[i]; |
219 | 44.9M | c1 = dev_proc(dev, encode_color)(dev, v); |
220 | 44.9M | if (invert) { |
221 | 5.48M | level = pdht->components[i].corder.num_levels - level; |
222 | 5.48M | color_set_binary_halftone_component(pdevc, pdht, i, c1, c0, level); |
223 | 5.48M | } else |
224 | 39.4M | color_set_binary_halftone_component(pdevc, pdht, i, c0, c1, level); |
225 | | |
226 | 44.9M | return 1; |
227 | 44.9M | } |
228 | 44.9M | } |