/src/ghostpdl/base/gsbitcom.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 | | #include <assert.h> |
17 | | |
18 | | /* Oversampled bitmap compression */ |
19 | | #include "std.h" |
20 | | #include "gstypes.h" |
21 | | #include "gdebug.h" |
22 | | #include "gsbitops.h" /* for prototype */ |
23 | | |
24 | | /* |
25 | | * Define a compile-time option to reverse nibble order in alpha maps. |
26 | | * Note that this does not reverse bit order within nibbles. |
27 | | * This option is here for a very specialized purpose and does not |
28 | | * interact well with the rest of the code. |
29 | | */ |
30 | | #ifndef ALPHA_LSB_FIRST |
31 | | # define ALPHA_LSB_FIRST 0 |
32 | | #endif |
33 | | |
34 | | /* Count the number of 1-bits in a half-byte. */ |
35 | | static const byte half_byte_1s[16] = { |
36 | | 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 |
37 | | }; |
38 | | |
39 | | /* Count the number of trailing 1s in an up-to-5-bit value, -1. */ |
40 | | static const byte bits5_trailing_1s[32] = { |
41 | | 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 3, |
42 | | 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 4 |
43 | | }; |
44 | | |
45 | | /* Count the number of leading 1s in an up-to-5-bit value, -1. */ |
46 | | static const byte bits5_leading_1s[32] = { |
47 | | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
48 | | 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 4 |
49 | | }; |
50 | | |
51 | | /* |
52 | | * Compress a value between 0 and 2^M to a value between 0 and 2^N-1. |
53 | | * Possible values of M are 1, 2, 3, or 4; of N are 1, 2, and 4. |
54 | | * The name of the table is compress_count_M_N. |
55 | | * As noted below, we require that N <= M. |
56 | | */ |
57 | | static const byte compress_1_1[3] = { |
58 | | 0, 1, 1 |
59 | | }; |
60 | | static const byte compress_2_1[5] = { |
61 | | 0, 0, 1, 1, 1 |
62 | | }; |
63 | | static const byte compress_2_2[5] = { |
64 | | 0, 1, 2, 2, 3 |
65 | | }; |
66 | | static const byte compress_3_1[9] = { |
67 | | 0, 0, 0, 0, 1, 1, 1, 1, 1 |
68 | | }; |
69 | | static const byte compress_3_2[9] = { |
70 | | 0, 0, 1, 1, 2, 2, 2, 3, 3 |
71 | | }; |
72 | | static const byte compress_4_1[17] = { |
73 | | 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 |
74 | | }; |
75 | | static const byte compress_4_2[17] = { |
76 | | 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3 |
77 | | }; |
78 | | static const byte compress_4_4[17] = { |
79 | | 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 10, 11, 12, 13, 14, 15 |
80 | | }; |
81 | | |
82 | | /* The table of tables is indexed by log2(N) and then by M-1. */ |
83 | | static const byte *const compress_tables[4][4] = { |
84 | | {compress_1_1, compress_2_1, compress_3_1, compress_4_1}, |
85 | | {0, compress_2_2, compress_3_2, compress_4_2}, |
86 | | {0, 0, 0, compress_4_4} |
87 | | }; |
88 | | |
89 | | /* |
90 | | * Compress an XxY-oversampled bitmap to Nx1 by counting 1-bits. The X and |
91 | | * Y oversampling factors are 1, 2, or 4, but may be different. N, the |
92 | | * resulting number of (alpha) bits per pixel, may be 1, 2, or 4; we allow |
93 | | * compression in place, in which case N must not exceed the X oversampling |
94 | | * factor. Width and height are the source dimensions, and hence reflect |
95 | | * the oversampling; both are multiples of the relevant scale factor. The |
96 | | * same is true for srcx. |
97 | | */ |
98 | | void |
99 | | bits_compress_scaled(const byte * src, int srcx, uint width, uint height, |
100 | | uint sraster, byte * dest, uint draster, |
101 | | const gs_log2_scale_point *plog2_scale, int log2_out_bits) |
102 | 0 | { |
103 | 0 | int log2_x = plog2_scale->x, log2_y = plog2_scale->y; |
104 | 0 | int xscale = 1 << log2_x; |
105 | 0 | int yscale = 1 << log2_y; |
106 | 0 | int out_bits = 1 << log2_out_bits; |
107 | | /* |
108 | | * The following two initializations are only needed (and the variables |
109 | | * are only used) if out_bits <= xscale. We do them in all cases only |
110 | | * to suppress bogus "possibly uninitialized variable" warnings from |
111 | | * certain compilers. |
112 | | */ |
113 | 0 | int input_byte_out_bits = out_bits << (3 - log2_x); |
114 | 0 | byte input_byte_out_mask = (1 << input_byte_out_bits) - 1; |
115 | 0 | const byte *table = |
116 | 0 | compress_tables[log2_out_bits][log2_x + log2_y - 1]; |
117 | 0 | uint sskip = sraster << log2_y; |
118 | 0 | uint dwidth = (width >> log2_x) << log2_out_bits; |
119 | 0 | uint dskip = draster - ((dwidth + 7) >> 3); |
120 | 0 | uint mask = (1 << xscale) - 1; |
121 | 0 | uint count_max = 1 << (log2_x + log2_y); |
122 | | /* |
123 | | * For the moment, we don't attempt to take advantage of the fact |
124 | | * that the input is aligned. |
125 | | */ |
126 | 0 | const byte *srow = src + (srcx >> 3); |
127 | 0 | int in_shift_initial = 8 - xscale - (srcx & 7); |
128 | 0 | int in_shift_check = (out_bits <= xscale ? 8 - xscale : -1); |
129 | 0 | byte *d = dest; |
130 | 0 | uint h; |
131 | | |
132 | | /* Assert some preconditions are satisfied: */ |
133 | | |
134 | | /* log2_x and log2_y must each be 0, 1 or 2. */ |
135 | 0 | assert(log2_x >= 0 && log2_x < 3); |
136 | 0 | assert(log2_y >= 0 && log2_y < 3); |
137 | | |
138 | | /* srcx and width must be multiple of xscale. */ |
139 | 0 | assert(srcx % xscale == 0); |
140 | 0 | assert(width % xscale == 0); |
141 | | |
142 | | /* height must be multiple of yscale. */ |
143 | 0 | assert(height % yscale == 0); |
144 | | |
145 | | /* because xscale is 1, 2 or 4 and srcx is a multiple of xscale, |
146 | | in_shift_initial ends up being constrained as follows: */ |
147 | 0 | if (log2_x == 0) { |
148 | | /* in_shift_initial is {0,1,2,3,4,5,6,7]} */ |
149 | 0 | assert(in_shift_initial >= 0 && in_shift_initial < 8); |
150 | 0 | } |
151 | 0 | if (log2_x == 1) { |
152 | | /* in_shift_initial is {0,2,4,6}. */ |
153 | 0 | assert(in_shift_initial >= 0 && in_shift_initial < 7 && in_shift_initial % 2 == 0); |
154 | 0 | } |
155 | 0 | if (log2_x == 2) { |
156 | | /* in_shift_initial is {0,4} */ |
157 | 0 | assert(in_shift_initial == 0 || in_shift_initial == 4); |
158 | 0 | } |
159 | |
|
160 | 0 | for (h = height; h; srow += sskip, h -= yscale) { |
161 | 0 | const byte *s = srow; |
162 | |
|
163 | | #if ALPHA_LSB_FIRST |
164 | | # define out_shift_initial 0 |
165 | | # define out_shift_update(out_shift, nbits) ((out_shift += (nbits)) >= 8) |
166 | | #else |
167 | 0 | # define out_shift_initial (8 - out_bits) |
168 | 0 | # define out_shift_update(out_shift, nbits) ((out_shift -= (nbits)) < 0) |
169 | 0 | #endif |
170 | 0 | int out_shift = out_shift_initial; |
171 | 0 | byte out = 0; |
172 | 0 | int in_shift = in_shift_initial; |
173 | 0 | int dw = 8 - (srcx & 7); |
174 | 0 | int w; |
175 | | |
176 | | /* Loop over source bytes. */ |
177 | 0 | for (w = width; w > 0; w -= dw, dw = 8) { |
178 | 0 | int index; |
179 | 0 | int in_shift_final = (w >= dw ? 0 : dw - w); |
180 | | |
181 | | /* |
182 | | * Check quickly for all-0s or all-1s, but only if each |
183 | | * input byte generates no more than one output byte, |
184 | | * we're at an input byte boundary, and we're processing |
185 | | * an entire input byte (i.e., this isn't a final |
186 | | * partial byte.) |
187 | | */ |
188 | 0 | if (in_shift == in_shift_check && in_shift_final == 0) |
189 | 0 | switch (*s) { |
190 | 0 | case 0: |
191 | 0 | for (index = sraster; index != sskip; index += sraster) |
192 | 0 | if (s[index] != 0) |
193 | 0 | goto p; |
194 | 0 | if (out_shift_update(out_shift, input_byte_out_bits)) |
195 | 0 | *d++ = out, out_shift &= 7, out = 0; |
196 | 0 | s++; |
197 | 0 | continue; |
198 | | #if !ALPHA_LSB_FIRST /* too messy to make it work */ |
199 | 0 | case 0xff: |
200 | 0 | for (index = sraster; index != sskip; index += sraster) |
201 | 0 | if (s[index] != 0xff) |
202 | 0 | goto p; |
203 | 0 | { |
204 | 0 | int shift = |
205 | 0 | (out_shift -= input_byte_out_bits) + out_bits; |
206 | |
|
207 | 0 | if (shift > 0) |
208 | 0 | out |= input_byte_out_mask << shift; |
209 | 0 | else { |
210 | 0 | out |= input_byte_out_mask >> -shift; |
211 | 0 | *d++ = out; |
212 | 0 | out_shift += 8; |
213 | 0 | out = input_byte_out_mask << (8 + shift); |
214 | 0 | } |
215 | 0 | } |
216 | 0 | s++; |
217 | 0 | continue; |
218 | 0 | #endif |
219 | 0 | default: |
220 | 0 | ; |
221 | 0 | } |
222 | 0 | p: /* Loop over source pixels within a byte. */ |
223 | 0 | do { |
224 | 0 | uint count; |
225 | |
|
226 | 0 | for (index = 0, count = 0; index != sskip; |
227 | 0 | index += sraster |
228 | 0 | ) { |
229 | | /* Coverity 94484 incorrectly thinks in_shift can be negative. */ |
230 | | /* coverity[negative_shift] */ |
231 | 0 | count += half_byte_1s[(s[index] >> in_shift) & mask]; |
232 | 0 | } |
233 | 0 | if (count != 0 && table[count] == 0) { /* Look at adjacent cells to help prevent */ |
234 | | /* dropouts. */ |
235 | 0 | uint orig_count = count; |
236 | 0 | uint shifted_mask = mask << in_shift; |
237 | 0 | byte in; |
238 | |
|
239 | 0 | if_debug3('B', "[B]count(%d,%d)=%d\n", |
240 | 0 | (width - w) / xscale, |
241 | 0 | (height - h) / yscale, count); |
242 | 0 | if (yscale > 1) { /* Look at the next "lower" cell. */ |
243 | 0 | if (h < height && (in = s[0] & shifted_mask) != 0) { |
244 | 0 | uint lower; |
245 | |
|
246 | 0 | for (index = 0, lower = 0; |
247 | 0 | -(index -= sraster) <= sskip && |
248 | 0 | (in &= s[index]) != 0; |
249 | 0 | ) |
250 | 0 | lower += half_byte_1s[in >> in_shift]; |
251 | 0 | if_debug1('B', "[B] lower adds %d\n", |
252 | 0 | lower); |
253 | 0 | if (lower <= orig_count) |
254 | 0 | count += lower; |
255 | 0 | } |
256 | | /* Look at the next "higher" cell. */ |
257 | 0 | if (h > yscale && (in = s[sskip - sraster] & shifted_mask) != 0) { |
258 | 0 | uint upper; |
259 | |
|
260 | 0 | for (index = sskip, upper = 0; |
261 | 0 | index < sskip << 1 && |
262 | 0 | (in &= s[index]) != 0; |
263 | 0 | index += sraster |
264 | 0 | ) |
265 | 0 | upper += half_byte_1s[in >> in_shift]; |
266 | 0 | if_debug1('B', "[B] upper adds %d\n", |
267 | 0 | upper); |
268 | 0 | if (upper < orig_count) |
269 | 0 | count += upper; |
270 | 0 | } |
271 | 0 | } |
272 | 0 | if (xscale > 1) { |
273 | 0 | uint mask1 = (mask << 1) + 1; |
274 | | |
275 | | /* Look at the next cell to the left. */ |
276 | 0 | if (w < width) { |
277 | 0 | int lshift = in_shift + xscale - 1; |
278 | 0 | uint left; |
279 | |
|
280 | 0 | for (index = 0, left = 0; |
281 | 0 | index < sskip; index += sraster |
282 | 0 | ) { |
283 | 0 | uint bits = |
284 | 0 | ((s[index - 1] << 8) + |
285 | 0 | s[index]) >> lshift; |
286 | |
|
287 | 0 | left += bits5_trailing_1s[bits & mask1]; |
288 | 0 | } |
289 | 0 | if_debug1('B', "[B] left adds %d\n", |
290 | 0 | left); |
291 | 0 | if (left < orig_count) |
292 | 0 | count += left; |
293 | 0 | } |
294 | | /* Look at the next cell to the right. */ |
295 | 0 | if (w > xscale) { |
296 | 0 | int rshift = in_shift - xscale + 8; |
297 | 0 | uint right; |
298 | |
|
299 | 0 | for (index = 0, right = 0; |
300 | 0 | index < sskip; index += sraster |
301 | 0 | ) { |
302 | 0 | uint bits = |
303 | 0 | ((s[index] << 8) + |
304 | 0 | s[index + 1]) >> rshift; |
305 | |
|
306 | 0 | right += bits5_leading_1s[(bits & mask1) << (4 - xscale)]; |
307 | 0 | } |
308 | 0 | if_debug1('B', "[B] right adds %d\n", |
309 | 0 | right); |
310 | 0 | if (right <= orig_count) |
311 | 0 | count += right; |
312 | 0 | } |
313 | 0 | } |
314 | 0 | if (count > count_max) |
315 | 0 | count = count_max; |
316 | 0 | } |
317 | 0 | out += table[count] << out_shift; |
318 | 0 | if (out_shift_update(out_shift, out_bits)) |
319 | 0 | *d++ = out, out_shift &= 7, out = 0; |
320 | 0 | } |
321 | 0 | while ((in_shift -= xscale) >= in_shift_final); |
322 | 0 | s++, in_shift += 8; |
323 | 0 | } |
324 | 0 | if (out_shift != out_shift_initial) |
325 | 0 | *d++ = out; |
326 | 0 | for (w = dskip; w != 0; w--) |
327 | 0 | *d++ = 0; |
328 | 0 | #undef out_shift_initial |
329 | 0 | #undef out_shift_update |
330 | 0 | } |
331 | 0 | } |