/src/ghostpdl/base/gximdecode.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2014-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 | | /* Methods for decoding and unpacking image data. Used for color |
17 | | monitoring in clist and for creating TIFF files for xpswrite device */ |
18 | | |
19 | | #include "gximdecode.h" |
20 | | #include "string_.h" |
21 | | |
22 | | /* We need to have the unpacking proc so that we can monitor the data for color |
23 | | or decode during xpswrite */ |
24 | | void |
25 | | get_unpack_proc(gx_image_enum_common_t *pie, image_decode_t *imd, |
26 | 2.03k | gs_image_format_t format, const float *decode) { |
27 | | |
28 | 2.03k | static sample_unpack_proc_t procs[2][6] = { |
29 | 2.03k | { sample_unpack_1, sample_unpack_2, |
30 | 2.03k | sample_unpack_4, sample_unpack_8, |
31 | 2.03k | sample_unpack_12, sample_unpackicc_16 |
32 | 2.03k | }, |
33 | 2.03k | { sample_unpack_1_interleaved, sample_unpack_2_interleaved, |
34 | 2.03k | sample_unpack_4_interleaved, sample_unpack_8_interleaved, |
35 | 2.03k | sample_unpack_12, sample_unpackicc_16 |
36 | 2.03k | } }; |
37 | 2.03k | int num_planes = pie->num_planes; |
38 | 2.03k | bool interleaved = (num_planes == 1 && pie->plane_depths[0] != imd->bps); |
39 | 2.03k | int i; |
40 | 2.03k | int index_bps = (imd->bps < 8 ? imd->bps >> 1 : (imd->bps >> 2) + 1); |
41 | 2.03k | int log2_xbytes = (imd->bps <= 8 ? 0 : arch_log2_sizeof_frac); |
42 | | |
43 | 2.03k | imd->unpack = NULL; |
44 | 2.03k | if (index_bps < 0 || index_bps > 5) |
45 | 0 | return; |
46 | | |
47 | 2.03k | switch (format) { |
48 | 2.03k | case gs_image_format_chunky: |
49 | 2.03k | imd->spread = 1 << log2_xbytes; |
50 | 2.03k | break; |
51 | 0 | case gs_image_format_component_planar: |
52 | 0 | imd->spread = (imd->spp) << log2_xbytes; |
53 | 0 | break; |
54 | 0 | case gs_image_format_bit_planar: |
55 | 0 | imd->spread = (imd->spp) << log2_xbytes; |
56 | 0 | break; |
57 | 0 | default: |
58 | 0 | imd->spread = 0; |
59 | 2.03k | } |
60 | | |
61 | 2.03k | if (interleaved) { |
62 | 1.49k | int num_components = pie->plane_depths[0] / imd->bps; |
63 | | |
64 | 4.53k | for (i = 1; i < num_components; i++) { |
65 | 3.04k | if (decode[0] != decode[i * 2 + 0] || |
66 | 3.04k | decode[1] != decode[i * 2 + 1]) |
67 | 0 | break; |
68 | 3.04k | } |
69 | 1.49k | if (i == num_components) |
70 | 1.49k | interleaved = false; /* Use single table. */ |
71 | 1.49k | } |
72 | 2.03k | imd->unpack = procs[interleaved][index_bps]; |
73 | 2.03k | } |
74 | | |
75 | | /* We also need the mapping method for the unpacking proc */ |
76 | | void |
77 | | get_map(image_decode_t *imd, gs_image_format_t format, const float *decode) |
78 | 2.03k | { |
79 | 2.03k | int ci = 0; |
80 | 2.03k | int decode_type; |
81 | 2.03k | int bps = imd->bps; |
82 | 2.03k | int spp = imd->spp; |
83 | 2.03k | static const float default_decode[] = { |
84 | 2.03k | 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0 |
85 | 2.03k | }; |
86 | 2.03k | const float *this_decode = &decode[ci * 2]; |
87 | 2.03k | const float *map_decode; /* decoding used to */ |
88 | | /* construct the expansion map */ |
89 | 2.03k | const float *real_decode; /* decoding for expanded samples */ |
90 | | |
91 | 2.03k | decode_type = 3; /* 0=custom, 1=identity, 2=inverted, 3=impossible */ |
92 | 5.55k | for (ci = 0; ci < spp; ci += 2) { |
93 | 3.52k | decode_type &= (decode[ci] == 0. && decode[ci + 1] == 1.) | |
94 | 3.52k | (decode[ci] == 1. && decode[ci + 1] == 0.) << 1; |
95 | 3.52k | } |
96 | | |
97 | | /* Initialize the maps from samples to intensities. */ |
98 | 7.11k | for (ci = 0; ci < spp; ci++) { |
99 | 5.08k | sample_map *pmap = &imd->map[ci]; |
100 | | |
101 | 5.08k | if (bps > 8) |
102 | 0 | imd->applymap = applymap16; |
103 | 5.08k | else |
104 | 5.08k | imd->applymap = applymap8; |
105 | | |
106 | | /* If the decoding is [0 1] or [1 0], we can fold it */ |
107 | | /* into the expansion of the sample values; */ |
108 | | /* otherwise, we have to use the floating point method. */ |
109 | | |
110 | 5.08k | this_decode = &decode[ci * 2]; |
111 | | |
112 | 5.08k | map_decode = real_decode = this_decode; |
113 | 5.08k | if (!(decode_type & 1)) { |
114 | 81 | if ((decode_type & 2) && bps <= 8) { |
115 | 79 | real_decode = default_decode; |
116 | 79 | } |
117 | 2 | else { |
118 | 2 | map_decode = default_decode; |
119 | 2 | } |
120 | 81 | } |
121 | 5.08k | if (bps > 2 || format != gs_image_format_chunky) { |
122 | 4.99k | if (bps <= 8) |
123 | 4.99k | image_init_map(&pmap->table.lookup8[0], 1 << bps, |
124 | 4.99k | map_decode); |
125 | 4.99k | } |
126 | 90 | else { /* The map index encompasses more than one pixel. */ |
127 | 90 | byte map[4]; |
128 | 90 | register int i; |
129 | | |
130 | 90 | image_init_map(&map[0], 1 << bps, map_decode); |
131 | 90 | switch (bps) { |
132 | 89 | case 1: |
133 | 89 | { |
134 | 89 | register bits32 *p = &pmap->table.lookup4x1to32[0]; |
135 | | |
136 | 89 | if (map[0] == 0 && map[1] == 0xff) |
137 | 85 | memcpy((byte *)p, lookup4x1to32_identity, 16 * 4); |
138 | 4 | else if (map[0] == 0xff && map[1] == 0) |
139 | 4 | memcpy((byte *)p, lookup4x1to32_inverted, 16 * 4); |
140 | 0 | else |
141 | 0 | for (i = 0; i < 16; i++, p++) |
142 | 0 | ((byte *)p)[0] = map[i >> 3], |
143 | 0 | ((byte *)p)[1] = map[(i >> 2) & 1], |
144 | 0 | ((byte *)p)[2] = map[(i >> 1) & 1], |
145 | 0 | ((byte *)p)[3] = map[i & 1]; |
146 | 89 | } |
147 | 89 | break; |
148 | 1 | case 2: |
149 | 1 | { |
150 | 1 | register bits16 *p = &pmap->table.lookup2x2to16[0]; |
151 | | |
152 | 17 | for (i = 0; i < 16; i++, p++) |
153 | 16 | ((byte *)p)[0] = map[i >> 2], |
154 | 16 | ((byte *)p)[1] = map[i & 3]; |
155 | 1 | } |
156 | 1 | break; |
157 | 90 | } |
158 | 90 | } |
159 | 5.08k | pmap->decode_base /* = decode_lookup[0] */ = real_decode[0]; |
160 | 5.08k | pmap->decode_factor = |
161 | 5.08k | (real_decode[1] - real_decode[0]) / |
162 | 5.08k | (bps <= 8 ? 255.0 : (float)frac_1); |
163 | 5.08k | pmap->decode_max /* = decode_lookup[15] */ = real_decode[1]; |
164 | 5.08k | if (decode_type) { |
165 | 5.07k | pmap->decoding = sd_none; |
166 | 5.07k | pmap->inverted = map_decode[0] != 0; |
167 | 5.07k | } |
168 | 2 | else if (bps <= 4) { |
169 | 0 | int step = 15 / ((1 << bps) - 1); |
170 | 0 | int i; |
171 | |
|
172 | 0 | pmap->decoding = sd_lookup; |
173 | 0 | for (i = 15 - step; i > 0; i -= step) |
174 | 0 | pmap->decode_lookup[i] = pmap->decode_base + |
175 | 0 | i * (255.0 / 15) * pmap->decode_factor; |
176 | 0 | } |
177 | 2 | else |
178 | 2 | pmap->decoding = sd_compute; |
179 | 5.08k | } |
180 | 2.03k | } |
181 | | |
182 | | /* We only provide 8 or 16 bit output with the application of the mapping */ |
183 | | void applymap8(sample_map map[], const void *psrc_in, int spp, void *pdes, |
184 | | void *bufend) |
185 | 1.53M | { |
186 | 1.53M | byte* psrc = (byte*)psrc_in; |
187 | 1.53M | byte *curr_pos = (byte*) pdes; |
188 | 1.53M | int k; |
189 | 1.53M | float temp; |
190 | | |
191 | 2.54G | while (curr_pos < (byte*) bufend) { |
192 | 9.93G | for (k = 0; k < spp; k++) { |
193 | 7.39G | switch (map[k].decoding) { |
194 | 7.39G | case sd_none: |
195 | 7.39G | *curr_pos = *psrc; |
196 | 7.39G | break; |
197 | 0 | case sd_lookup: |
198 | 0 | temp = map[k].decode_lookup[(*psrc) >> 4] * 255; |
199 | 0 | if (temp > 255) temp = 255; |
200 | 0 | if (temp < 0) temp = 0; |
201 | 0 | *curr_pos = (byte)temp; |
202 | 0 | break; |
203 | 3.12k | case sd_compute: |
204 | 3.12k | temp = map[k].decode_base + |
205 | 3.12k | *(psrc) * map[k].decode_factor; |
206 | 3.12k | temp *= 255; |
207 | 3.12k | if (temp > 255) temp = 255; |
208 | 3.12k | if (temp < 0) temp = 0; |
209 | 3.12k | *curr_pos = (byte)temp; |
210 | 3.12k | default: |
211 | 3.12k | break; |
212 | 7.39G | } |
213 | 7.39G | curr_pos++; |
214 | 7.39G | psrc++; |
215 | 7.39G | } |
216 | 2.54G | } |
217 | 1.53M | } |
218 | | |
219 | | void applymap16(sample_map map[], const void *psrc_in, int spp, void *pdes, |
220 | | void *bufend) |
221 | 0 | { |
222 | 0 | unsigned short *curr_pos = (unsigned short*)pdes; |
223 | 0 | unsigned short *psrc = (unsigned short*)psrc_in; |
224 | 0 | int k; |
225 | 0 | float temp; |
226 | |
|
227 | 0 | while (curr_pos < (unsigned short*) bufend) { |
228 | 0 | for (k = 0; k < spp; k++) { |
229 | 0 | switch (map[k].decoding) { |
230 | 0 | case sd_none: |
231 | 0 | *curr_pos = *psrc; |
232 | 0 | break; |
233 | 0 | case sd_lookup: |
234 | 0 | temp = map[k].decode_lookup[*(psrc) >> 4] * 65535.0; |
235 | 0 | if (temp > 65535) temp = 65535; |
236 | 0 | if (temp < 0) temp = 0; |
237 | 0 | *curr_pos = (unsigned short)temp; |
238 | 0 | break; |
239 | 0 | case sd_compute: |
240 | 0 | temp = map[k].decode_base + |
241 | 0 | *psrc * map[k].decode_factor; |
242 | 0 | temp *= 65535; |
243 | 0 | if (temp > 65535) temp = 65535; |
244 | 0 | if (temp < 0) temp = 0; |
245 | 0 | *curr_pos = (unsigned short)temp; |
246 | 0 | default: |
247 | 0 | break; |
248 | 0 | } |
249 | 0 | curr_pos++; |
250 | 0 | psrc++; |
251 | 0 | } |
252 | 0 | } |
253 | 0 | } |