/src/mupdf/source/fitz/draw-unpack.c
Line | Count | Source |
1 | | // Copyright (C) 2004-2021 Artifex Software, Inc. |
2 | | // |
3 | | // This file is part of MuPDF. |
4 | | // |
5 | | // MuPDF is free software: you can redistribute it and/or modify it under the |
6 | | // terms of the GNU Affero General Public License as published by the Free |
7 | | // Software Foundation, either version 3 of the License, or (at your option) |
8 | | // any later version. |
9 | | // |
10 | | // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY |
11 | | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
12 | | // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more |
13 | | // details. |
14 | | // |
15 | | // You should have received a copy of the GNU Affero General Public License |
16 | | // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html> |
17 | | // |
18 | | // Alternative licensing terms are available from the licensor. |
19 | | // For commercial licensing, see <https://www.artifex.com/> or contact |
20 | | // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, |
21 | | // CA 94129, USA, for further information. |
22 | | |
23 | | #include "mupdf/fitz.h" |
24 | | #include "draw-imp.h" |
25 | | |
26 | | #include <string.h> |
27 | | |
28 | | /* Unpack image samples and optionally pad pixels with opaque alpha */ |
29 | | |
30 | 2.04k | #define get1(buf,x) ((buf[x >> 3] >> ( 7 - (x & 7) ) ) & 1 ) |
31 | 0 | #define get2(buf,x) ((buf[x >> 2] >> ( ( 3 - (x & 3) ) << 1 ) ) & 3 ) |
32 | 0 | #define get4(buf,x) ((buf[x >> 1] >> ( ( 1 - (x & 1) ) << 2 ) ) & 15 ) |
33 | 0 | #define get8(buf,x) (buf[x]) |
34 | 0 | #define get16(buf,x) (buf[x << 1]) |
35 | 0 | #define get24(buf,x) (buf[(x << 1) + x]) |
36 | 0 | #define get32(buf,x) (buf[x << 2]) |
37 | | |
38 | | static unsigned char get1_tab_1[256][8]; |
39 | | static unsigned char get1_tab_1p[256][16]; |
40 | | static unsigned char get1_tab_255[256][8]; |
41 | | static unsigned char get1_tab_255p[256][16]; |
42 | | |
43 | | /* |
44 | | Bug 697012 shows that the unpacking code can confuse valgrind due |
45 | | to the use of undefined bits in the padding at the end of lines. |
46 | | We unpack from bits to bytes by copying from a lookup table. |
47 | | Valgrind is not capable of understanding that it doesn't matter |
48 | | what the undefined bits are, as the bytes we copy that correspond |
49 | | to the defined bits will always agree regardless of these |
50 | | undefined bits by construction of the table. |
51 | | |
52 | | We therefore have a VGMASK macro that explicitly masks off these |
53 | | bits in PACIFY_VALGRIND builds. |
54 | | */ |
55 | | #ifdef PACIFY_VALGRIND |
56 | | static const unsigned char mask[9] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; |
57 | 5.48k | #define VGMASK(v,m) (v & mask[(m)]) |
58 | | #else |
59 | | #define VGMASK(v,m) (v) |
60 | | #endif |
61 | | |
62 | | static void |
63 | | init_get1_tables(void) |
64 | 103 | { |
65 | 103 | static int once = 0; |
66 | 103 | unsigned char bits[1]; |
67 | 103 | int i, k, x; |
68 | | |
69 | | /* TODO: mutex lock here */ |
70 | | |
71 | 103 | if (once) |
72 | 102 | return; |
73 | | |
74 | 257 | for (i = 0; i < 256; i++) |
75 | 256 | { |
76 | 256 | bits[0] = i; |
77 | 2.30k | for (k = 0; k < 8; k++) |
78 | 2.04k | { |
79 | 2.04k | x = get1(bits, k); |
80 | | |
81 | 2.04k | get1_tab_1[i][k] = x; |
82 | 2.04k | get1_tab_1p[i][k * 2] = x; |
83 | 2.04k | get1_tab_1p[i][k * 2 + 1] = 255; |
84 | | |
85 | 2.04k | get1_tab_255[i][k] = x * 255; |
86 | 2.04k | get1_tab_255p[i][k * 2] = x * 255; |
87 | 2.04k | get1_tab_255p[i][k * 2 + 1] = 255; |
88 | 2.04k | } |
89 | 256 | } |
90 | | |
91 | 1 | once = 1; |
92 | 1 | } |
93 | | |
94 | | static void |
95 | | fz_unpack_mono_line_unscaled(unsigned char *dp, unsigned char *sp, int w, int n, int depth, int scale, int pad, int skip) |
96 | 0 | { |
97 | 0 | int w3 = w >> 3; |
98 | 0 | int x; |
99 | |
|
100 | 0 | for (x = 0; x < w3; x++) |
101 | 0 | { |
102 | 0 | memcpy(dp, get1_tab_1[*sp++], 8); |
103 | 0 | dp += 8; |
104 | 0 | } |
105 | 0 | x = x << 3; |
106 | 0 | if (x < w) |
107 | 0 | memcpy(dp, get1_tab_1[VGMASK(*sp, w - x)], w - x); |
108 | 0 | } |
109 | | |
110 | | static void |
111 | | fz_unpack_mono_line_scaled(unsigned char *dp, unsigned char *sp, int w, int n, int depth, int scale, int pad, int skip) |
112 | 6.29k | { |
113 | 6.29k | int w3 = w >> 3; |
114 | 6.29k | int x; |
115 | | |
116 | 39.3k | for (x = 0; x < w3; x++) |
117 | 33.0k | { |
118 | 33.0k | memcpy(dp, get1_tab_255[*sp++], 8); |
119 | 33.0k | dp += 8; |
120 | 33.0k | } |
121 | 6.29k | x = x << 3; |
122 | 6.29k | if (x < w) |
123 | 5.48k | memcpy(dp, get1_tab_255[VGMASK(*sp, w - x)], w - x); |
124 | 6.29k | } |
125 | | |
126 | | static void |
127 | | fz_unpack_mono_line_unscaled_with_padding(unsigned char *dp, unsigned char *sp, int w, int n, int depth, int scale, int pad, int skip) |
128 | 0 | { |
129 | 0 | int w3 = w >> 3; |
130 | 0 | int x; |
131 | |
|
132 | 0 | for (x = 0; x < w3; x++) |
133 | 0 | { |
134 | 0 | memcpy(dp, get1_tab_1p[*sp++], 16); |
135 | 0 | dp += 16; |
136 | 0 | } |
137 | 0 | x = x << 3; |
138 | 0 | if (x < w) |
139 | 0 | memcpy(dp, get1_tab_1p[VGMASK(*sp, w - x)], (w - x) << 1); |
140 | 0 | } |
141 | | |
142 | | static void |
143 | | fz_unpack_mono_line_scaled_with_padding(unsigned char *dp, unsigned char *sp, int w, int n, int depth, int scale, int pad, int skip) |
144 | 0 | { |
145 | 0 | int w3 = w >> 3; |
146 | 0 | int x; |
147 | |
|
148 | 0 | for (x = 0; x < w3; x++) |
149 | 0 | { |
150 | 0 | memcpy(dp, get1_tab_255p[*sp++], 16); |
151 | 0 | dp += 16; |
152 | 0 | } |
153 | 0 | x = x << 3; |
154 | 0 | if (x < w) |
155 | 0 | memcpy(dp, get1_tab_255p[VGMASK(*sp, w - x)], (w - x) << 1); |
156 | 0 | } |
157 | | |
158 | | static void |
159 | | fz_unpack_line(unsigned char *dp, unsigned char *sp, int w, int n, int depth, int scale, int pad, int skip) |
160 | 0 | { |
161 | 0 | int len = w * n; |
162 | 0 | while (len--) |
163 | 0 | *dp++ = *sp++; |
164 | 0 | } |
165 | | |
166 | | static void |
167 | | fz_unpack_line_with_padding(unsigned char *dp, unsigned char *sp, int w, int n, int depth, int scale, int pad, int skip) |
168 | 0 | { |
169 | 0 | int x, k; |
170 | |
|
171 | 0 | for (x = 0; x < w; x++) |
172 | 0 | { |
173 | 0 | for (k = 0; k < n; k++) |
174 | 0 | *dp++ = *sp++; |
175 | 0 | *dp++ = 255; |
176 | 0 | } |
177 | 0 | } |
178 | | |
179 | | static void |
180 | | fz_unpack_any_l2depth(unsigned char *dp, unsigned char *sp, int w, int n, int depth, int scale, int pad, int skip) |
181 | 0 | { |
182 | 0 | unsigned char *p = dp; |
183 | 0 | int b = 0; |
184 | 0 | int x, k; |
185 | |
|
186 | 0 | for (x = 0; x < w; x++) |
187 | 0 | { |
188 | 0 | for (k = 0; k < n; k++) |
189 | 0 | { |
190 | 0 | switch (depth) |
191 | 0 | { |
192 | 0 | case 1: *p++ = get1(sp, b) * scale; break; |
193 | 0 | case 2: *p++ = get2(sp, b) * scale; break; |
194 | 0 | case 4: *p++ = get4(sp, b) * scale; break; |
195 | 0 | case 8: *p++ = get8(sp, b); break; |
196 | 0 | case 16: *p++ = get16(sp, b); break; |
197 | 0 | case 24: *p++ = get24(sp, b); break; |
198 | 0 | case 32: *p++ = get32(sp, b); break; |
199 | 0 | } |
200 | 0 | b++; |
201 | 0 | } |
202 | 0 | b += skip; |
203 | 0 | if (pad) |
204 | 0 | *p++ = 255; |
205 | 0 | } |
206 | 0 | } |
207 | | |
208 | | typedef void (*fz_unpack_line_fn)(unsigned char *dp, unsigned char *sp, int w, int n, int depth, int scale, int pad, int skip); |
209 | | |
210 | | void |
211 | | fz_unpack_tile(fz_context *ctx, fz_pixmap *dst, unsigned char *src, int n, int depth, size_t stride, int scale) |
212 | 0 | { |
213 | 0 | unsigned char *sp = src; |
214 | 0 | unsigned char *dp = dst->samples; |
215 | 0 | fz_unpack_line_fn unpack_line = NULL; |
216 | 0 | int pad, y, skip; |
217 | 0 | int w = dst->w; |
218 | 0 | int h = dst->h; |
219 | |
|
220 | 0 | pad = 0; |
221 | 0 | skip = 0; |
222 | 0 | if (dst->n > n) |
223 | 0 | pad = 255; |
224 | 0 | if (dst->n < n) |
225 | 0 | { |
226 | 0 | skip = n - dst->n; |
227 | 0 | n = dst->n; |
228 | 0 | } |
229 | |
|
230 | 0 | if (depth == 1) |
231 | 0 | init_get1_tables(); |
232 | |
|
233 | 0 | if (scale == 0) |
234 | 0 | { |
235 | 0 | switch (depth) |
236 | 0 | { |
237 | 0 | case 1: scale = 255; break; |
238 | 0 | case 2: scale = 85; break; |
239 | 0 | case 4: scale = 17; break; |
240 | 0 | } |
241 | 0 | } |
242 | | |
243 | 0 | if (n == 1 && depth == 1 && scale == 1 && !pad && !skip) |
244 | 0 | unpack_line = fz_unpack_mono_line_unscaled; |
245 | 0 | else if (n == 1 && depth == 1 && scale == 255 && !pad && !skip) |
246 | 0 | unpack_line = fz_unpack_mono_line_scaled; |
247 | 0 | else if (n == 1 && depth == 1 && scale == 1 && pad && !skip) |
248 | 0 | unpack_line = fz_unpack_mono_line_unscaled_with_padding; |
249 | 0 | else if (n == 1 && depth == 1 && scale == 255 && pad && !skip) |
250 | 0 | unpack_line = fz_unpack_mono_line_scaled_with_padding; |
251 | 0 | else if (depth == 8 && !pad && !skip) |
252 | 0 | unpack_line = fz_unpack_line; |
253 | 0 | else if (depth == 8 && pad && !skip) |
254 | 0 | unpack_line = fz_unpack_line_with_padding; |
255 | 0 | else if (depth == 1 || depth == 2 || depth == 4 || depth == 8 || depth == 16 || depth == 24 || depth == 32) |
256 | 0 | unpack_line = fz_unpack_any_l2depth; |
257 | |
|
258 | 0 | if (unpack_line) |
259 | 0 | { |
260 | 0 | for (y = 0; y < h; y++, sp += stride, dp += dst->stride) |
261 | 0 | unpack_line(dp, sp, w, n, depth, scale, pad, skip); |
262 | 0 | } |
263 | 0 | else if (depth > 0 && depth <= 8 * (int)sizeof(int)) |
264 | 0 | { |
265 | 0 | fz_stream *stm; |
266 | 0 | int x, k; |
267 | 0 | size_t skipbits = 8 * stride - (size_t)w * n * depth; |
268 | |
|
269 | 0 | if (skipbits > 32) |
270 | 0 | fz_throw(ctx, FZ_ERROR_ARGUMENT, "Inappropriate stride!"); |
271 | | |
272 | 0 | stm = fz_open_memory(ctx, sp, h * stride); |
273 | 0 | fz_try(ctx) |
274 | 0 | { |
275 | 0 | for (y = 0; y < h; y++) |
276 | 0 | { |
277 | 0 | for (x = 0; x < w; x++) |
278 | 0 | { |
279 | 0 | for (k = 0; k < n; k++) |
280 | 0 | { |
281 | 0 | if (depth <= 8) |
282 | 0 | *dp++ = fz_read_bits(ctx, stm, depth) << (8 - depth); |
283 | 0 | else |
284 | 0 | *dp++ = fz_read_bits(ctx, stm, depth) >> (depth - 8); |
285 | 0 | } |
286 | 0 | if (pad) |
287 | 0 | *dp++ = 255; |
288 | 0 | } |
289 | |
|
290 | 0 | dp += dst->stride - (size_t)w * (n + (pad > 0)); |
291 | 0 | (void) fz_read_bits(ctx, stm, (int)skipbits); |
292 | 0 | } |
293 | 0 | } |
294 | 0 | fz_always(ctx) |
295 | 0 | fz_drop_stream(ctx, stm); |
296 | 0 | fz_catch(ctx) |
297 | 0 | fz_rethrow(ctx); |
298 | 0 | } |
299 | 0 | else |
300 | 0 | fz_throw(ctx, FZ_ERROR_ARGUMENT, "cannot unpack tile with %d bits per component", depth); |
301 | 0 | } |
302 | | |
303 | | /* Apply decode array */ |
304 | | |
305 | | void |
306 | | fz_decode_indexed_tile(fz_context *ctx, fz_pixmap *pix, const float *decode, int maxval) |
307 | 0 | { |
308 | 0 | int add[FZ_MAX_COLORS]; |
309 | 0 | int mul[FZ_MAX_COLORS]; |
310 | 0 | unsigned char *p = pix->samples; |
311 | 0 | size_t stride = pix->stride - pix->w * (size_t)pix->n; |
312 | 0 | int len; |
313 | 0 | int pn = pix->n; |
314 | 0 | int n = pn - pix->alpha; |
315 | 0 | int needed; |
316 | 0 | int k; |
317 | 0 | int h; |
318 | |
|
319 | 0 | needed = 0; |
320 | 0 | for (k = 0; k < n; k++) |
321 | 0 | { |
322 | 0 | int min = decode[k * 2] * 256; |
323 | 0 | int max = decode[k * 2 + 1] * 256; |
324 | 0 | add[k] = min; |
325 | 0 | mul[k] = (max - min) / maxval; |
326 | 0 | needed |= min != 0 || max != maxval * 256; |
327 | 0 | } |
328 | |
|
329 | 0 | if (!needed) |
330 | 0 | return; |
331 | | |
332 | 0 | h = pix->h; |
333 | 0 | while (h--) |
334 | 0 | { |
335 | 0 | len = pix->w; |
336 | 0 | while (len--) |
337 | 0 | { |
338 | 0 | for (k = 0; k < n; k++) |
339 | 0 | { |
340 | 0 | int value = (add[k] + (((p[k] << 8) * mul[k]) >> 8)) >> 8; |
341 | 0 | p[k] = fz_clampi(value, 0, 255); |
342 | 0 | } |
343 | 0 | p += pn; |
344 | 0 | } |
345 | 0 | p += stride; |
346 | 0 | } |
347 | 0 | } |
348 | | |
349 | | void |
350 | | fz_decode_tile(fz_context *ctx, fz_pixmap *pix, const float *decode) |
351 | 109 | { |
352 | 109 | int add[FZ_MAX_COLORS]; |
353 | 109 | int mul[FZ_MAX_COLORS]; |
354 | 109 | unsigned char *p = pix->samples; |
355 | 109 | size_t stride = pix->stride - pix->w * (size_t)pix->n; |
356 | 109 | int len; |
357 | 109 | int n = fz_maxi(1, pix->n - pix->alpha); |
358 | 109 | int k; |
359 | 109 | int h; |
360 | | |
361 | 218 | for (k = 0; k < n; k++) |
362 | 109 | { |
363 | 109 | int min = decode[k * 2] * 255; |
364 | 109 | int max = decode[k * 2 + 1] * 255; |
365 | 109 | add[k] = min; |
366 | 109 | mul[k] = max - min; |
367 | 109 | } |
368 | | |
369 | 109 | h = pix->h; |
370 | 6.64k | while (h--) |
371 | 6.53k | { |
372 | 6.53k | len = pix->w; |
373 | 1.50M | while (len--) |
374 | 1.49M | { |
375 | 2.98M | for (k = 0; k < n; k++) |
376 | 1.49M | { |
377 | 1.49M | int value = add[k] + fz_mul255(p[k], mul[k]); |
378 | 1.49M | p[k] = fz_clampi(value, 0, 255); |
379 | 1.49M | } |
380 | 1.49M | p += pix->n; |
381 | 1.49M | } |
382 | 6.53k | p += stride; |
383 | 6.53k | } |
384 | 109 | } |
385 | | |
386 | | typedef struct |
387 | | { |
388 | | fz_stream *src; |
389 | | int depth; |
390 | | int w; |
391 | | int h; |
392 | | int n; |
393 | | int skip; |
394 | | int pad; |
395 | | int scale; |
396 | | size_t src_stride; |
397 | | size_t dst_stride; |
398 | | fz_unpack_line_fn unpack; |
399 | | unsigned char buf[1]; |
400 | | } unpack_state; |
401 | | |
402 | | static int |
403 | | unpack_next(fz_context *ctx, fz_stream *stm, size_t max) |
404 | 6.29k | { |
405 | 6.29k | unpack_state *state = (unpack_state *)stm->state; |
406 | 6.29k | size_t n = state->src_stride; |
407 | | |
408 | 6.29k | stm->rp = state->buf; |
409 | 6.29k | do |
410 | 6.29k | { |
411 | 6.29k | size_t a = fz_available(ctx, state->src, n); |
412 | 6.29k | if (a == 0) |
413 | 0 | return EOF; |
414 | 6.29k | if (a > n) |
415 | 2.50k | a = n; |
416 | 6.29k | memcpy(stm->rp, state->src->rp, a); |
417 | 6.29k | stm->rp += a; |
418 | 6.29k | state->src->rp += a; |
419 | 6.29k | n -= a; |
420 | 6.29k | } |
421 | 6.29k | while (n); |
422 | | |
423 | 6.29k | state->h--; |
424 | 6.29k | stm->pos += state->dst_stride; |
425 | 6.29k | stm->wp = stm->rp + state->dst_stride; |
426 | 6.29k | state->unpack(stm->rp, state->buf, state->w, state->n, state->depth, state->scale, state->pad, state->skip); |
427 | | |
428 | 6.29k | return *stm->rp++; |
429 | 6.29k | } |
430 | | |
431 | | static void |
432 | | unpack_drop(fz_context *ctx, void *state) |
433 | 103 | { |
434 | 103 | fz_free(ctx, state); |
435 | 103 | } |
436 | | |
437 | | fz_stream * |
438 | | fz_unpack_stream(fz_context *ctx, fz_stream *src, int depth, int w, int h, int n, int indexed, int pad, int skip) |
439 | 103 | { |
440 | 103 | uint64_t u64; |
441 | 103 | size_t src_stride, dst_stride; |
442 | 103 | unpack_state *state; |
443 | 103 | fz_unpack_line_fn unpack_line = NULL; |
444 | 103 | int scale = 1; |
445 | | |
446 | 103 | if (n < 1 || n > FZ_MAX_COLORS) |
447 | 0 | fz_throw(ctx, FZ_ERROR_ARGUMENT, "n out of range in fz_unpack_stream"); |
448 | 103 | if (depth < 1 || depth > 32) |
449 | 0 | fz_throw(ctx, FZ_ERROR_ARGUMENT, "depth out of range in fz_unpack_stream"); |
450 | | |
451 | 103 | if (fz_ckd_mul_u64(&u64, w, depth*n)) |
452 | 0 | fz_throw(ctx, FZ_ERROR_ARGUMENT, "area out of range in fz_unpack_stream"); |
453 | 103 | u64 = (u64+7)>>3; |
454 | 103 | if (u64 > SIZE_MAX) |
455 | 0 | fz_throw(ctx, FZ_ERROR_ARGUMENT, "area out of range in fz_unpack_stream"); |
456 | 103 | src_stride = (size_t)u64; |
457 | | |
458 | 103 | if (depth == 1) |
459 | 103 | init_get1_tables(); |
460 | | |
461 | 103 | if (!indexed) |
462 | 103 | switch (depth) |
463 | 103 | { |
464 | 103 | case 1: scale = 255; break; |
465 | 0 | case 2: scale = 85; break; |
466 | 0 | case 4: scale = 17; break; |
467 | 103 | } |
468 | | |
469 | 103 | if (fz_ckd_mul_size(&dst_stride, w, n + !!pad)) |
470 | 0 | fz_throw(ctx, FZ_ERROR_ARGUMENT, "dst_stride out of range in fz_unpack_stream"); |
471 | | |
472 | 103 | if (n == 1 && depth == 1 && scale == 1 && !pad && !skip) |
473 | 0 | unpack_line = fz_unpack_mono_line_unscaled; |
474 | 103 | else if (n == 1 && depth == 1 && scale == 255 && !pad && !skip) |
475 | 103 | unpack_line = fz_unpack_mono_line_scaled; |
476 | 0 | else if (n == 1 && depth == 1 && scale == 1 && pad && !skip) |
477 | 0 | unpack_line = fz_unpack_mono_line_unscaled_with_padding; |
478 | 0 | else if (n == 1 && depth == 1 && scale == 255 && pad && !skip) |
479 | 0 | unpack_line = fz_unpack_mono_line_scaled_with_padding; |
480 | 0 | else if (depth == 8 && !pad && !skip) |
481 | 0 | unpack_line = fz_unpack_line; |
482 | 0 | else if (depth == 8 && pad && !skip) |
483 | 0 | unpack_line = fz_unpack_line_with_padding; |
484 | 0 | else if (depth == 1 || depth == 2 || depth == 4 || depth == 8 || depth == 16 || depth == 24 || depth == 32) |
485 | 0 | unpack_line = fz_unpack_any_l2depth; |
486 | 0 | else |
487 | 0 | fz_throw(ctx, FZ_ERROR_ARGUMENT, "Unsupported combination in fz_unpack_stream"); |
488 | | |
489 | 103 | state = fz_malloc(ctx, sizeof(unpack_state) + dst_stride + src_stride); |
490 | 103 | state->src = src; |
491 | 103 | state->depth = depth; |
492 | 103 | state->w = w; |
493 | 103 | state->h = h; |
494 | 103 | state->n = n; |
495 | 103 | state->skip = skip; |
496 | 103 | state->pad = pad; |
497 | 103 | state->scale = scale; |
498 | 103 | state->unpack = unpack_line; |
499 | 103 | state->src_stride = src_stride; |
500 | 103 | state->dst_stride = dst_stride; |
501 | | |
502 | 103 | return fz_new_stream(ctx, state, unpack_next, unpack_drop); |
503 | 103 | } |