Mercurial > hgrepos > Python2 > PyMuPDF
diff mupdf-source/source/fitz/draw-unpack.c @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mupdf-source/source/fitz/draw-unpack.c Mon Sep 15 11:43:07 2025 +0200 @@ -0,0 +1,490 @@ +// Copyright (C) 2004-2021 Artifex Software, Inc. +// +// This file is part of MuPDF. +// +// MuPDF is free software: you can redistribute it and/or modify it under the +// terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) +// any later version. +// +// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License +// along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html> +// +// Alternative licensing terms are available from the licensor. +// For commercial licensing, see <https://www.artifex.com/> or contact +// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, +// CA 94129, USA, for further information. + +#include "mupdf/fitz.h" +#include "draw-imp.h" + +#include <string.h> + +/* Unpack image samples and optionally pad pixels with opaque alpha */ + +#define get1(buf,x) ((buf[x >> 3] >> ( 7 - (x & 7) ) ) & 1 ) +#define get2(buf,x) ((buf[x >> 2] >> ( ( 3 - (x & 3) ) << 1 ) ) & 3 ) +#define get4(buf,x) ((buf[x >> 1] >> ( ( 1 - (x & 1) ) << 2 ) ) & 15 ) +#define get8(buf,x) (buf[x]) +#define get16(buf,x) (buf[x << 1]) +#define get24(buf,x) (buf[(x << 1) + x]) +#define get32(buf,x) (buf[x << 2]) + +static unsigned char get1_tab_1[256][8]; +static unsigned char get1_tab_1p[256][16]; +static unsigned char get1_tab_255[256][8]; +static unsigned char get1_tab_255p[256][16]; + +/* + Bug 697012 shows that the unpacking code can confuse valgrind due + to the use of undefined bits in the padding at the end of lines. + We unpack from bits to bytes by copying from a lookup table. + Valgrind is not capable of understanding that it doesn't matter + what the undefined bits are, as the bytes we copy that correspond + to the defined bits will always agree regardless of these + undefined bits by construction of the table. + + We therefore have a VGMASK macro that explicitly masks off these + bits in PACIFY_VALGRIND builds. +*/ +#ifdef PACIFY_VALGRIND +static const unsigned char mask[9] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; +#define VGMASK(v,m) (v & mask[(m)]) +#else +#define VGMASK(v,m) (v) +#endif + +static void +init_get1_tables(void) +{ + static int once = 0; + unsigned char bits[1]; + int i, k, x; + + /* TODO: mutex lock here */ + + if (once) + return; + + for (i = 0; i < 256; i++) + { + bits[0] = i; + for (k = 0; k < 8; k++) + { + x = get1(bits, k); + + get1_tab_1[i][k] = x; + get1_tab_1p[i][k * 2] = x; + get1_tab_1p[i][k * 2 + 1] = 255; + + get1_tab_255[i][k] = x * 255; + get1_tab_255p[i][k * 2] = x * 255; + get1_tab_255p[i][k * 2 + 1] = 255; + } + } + + once = 1; +} + +static void +fz_unpack_mono_line_unscaled(unsigned char *dp, unsigned char *sp, int w, int n, int depth, int scale, int pad, int skip) +{ + int w3 = w >> 3; + int x; + + for (x = 0; x < w3; x++) + { + memcpy(dp, get1_tab_1[*sp++], 8); + dp += 8; + } + x = x << 3; + if (x < w) + memcpy(dp, get1_tab_1[VGMASK(*sp, w - x)], w - x); +} + +static void +fz_unpack_mono_line_scaled(unsigned char *dp, unsigned char *sp, int w, int n, int depth, int scale, int pad, int skip) +{ + int w3 = w >> 3; + int x; + + for (x = 0; x < w3; x++) + { + memcpy(dp, get1_tab_255[*sp++], 8); + dp += 8; + } + x = x << 3; + if (x < w) + memcpy(dp, get1_tab_255[VGMASK(*sp, w - x)], w - x); +} + +static void +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) +{ + int w3 = w >> 3; + int x; + + for (x = 0; x < w3; x++) + { + memcpy(dp, get1_tab_1p[*sp++], 16); + dp += 16; + } + x = x << 3; + if (x < w) + memcpy(dp, get1_tab_1p[VGMASK(*sp, w - x)], (w - x) << 1); +} + +static void +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) +{ + int w3 = w >> 3; + int x; + + for (x = 0; x < w3; x++) + { + memcpy(dp, get1_tab_255p[*sp++], 16); + dp += 16; + } + x = x << 3; + if (x < w) + memcpy(dp, get1_tab_255p[VGMASK(*sp, w - x)], (w - x) << 1); +} + +static void +fz_unpack_line(unsigned char *dp, unsigned char *sp, int w, int n, int depth, int scale, int pad, int skip) +{ + int len = w * n; + while (len--) + *dp++ = *sp++; +} + +static void +fz_unpack_line_with_padding(unsigned char *dp, unsigned char *sp, int w, int n, int depth, int scale, int pad, int skip) +{ + int x, k; + + for (x = 0; x < w; x++) + { + for (k = 0; k < n; k++) + *dp++ = *sp++; + *dp++ = 255; + } +} + +static void +fz_unpack_any_l2depth(unsigned char *dp, unsigned char *sp, int w, int n, int depth, int scale, int pad, int skip) +{ + unsigned char *p = dp; + int b = 0; + int x, k; + + for (x = 0; x < w; x++) + { + for (k = 0; k < n; k++) + { + switch (depth) + { + case 1: *p++ = get1(sp, b) * scale; break; + case 2: *p++ = get2(sp, b) * scale; break; + case 4: *p++ = get4(sp, b) * scale; break; + case 8: *p++ = get8(sp, b); break; + case 16: *p++ = get16(sp, b); break; + case 24: *p++ = get24(sp, b); break; + case 32: *p++ = get32(sp, b); break; + } + b++; + } + b += skip; + if (pad) + *p++ = 255; + } +} + +typedef void (*fz_unpack_line_fn)(unsigned char *dp, unsigned char *sp, int w, int n, int depth, int scale, int pad, int skip); + +void +fz_unpack_tile(fz_context *ctx, fz_pixmap *dst, unsigned char *src, int n, int depth, size_t stride, int scale) +{ + unsigned char *sp = src; + unsigned char *dp = dst->samples; + fz_unpack_line_fn unpack_line = NULL; + int pad, y, skip; + int w = dst->w; + int h = dst->h; + + pad = 0; + skip = 0; + if (dst->n > n) + pad = 255; + if (dst->n < n) + { + skip = n - dst->n; + n = dst->n; + } + + if (depth == 1) + init_get1_tables(); + + if (scale == 0) + { + switch (depth) + { + case 1: scale = 255; break; + case 2: scale = 85; break; + case 4: scale = 17; break; + } + } + + if (n == 1 && depth == 1 && scale == 1 && !pad && !skip) + unpack_line = fz_unpack_mono_line_unscaled; + else if (n == 1 && depth == 1 && scale == 255 && !pad && !skip) + unpack_line = fz_unpack_mono_line_scaled; + else if (n == 1 && depth == 1 && scale == 1 && pad && !skip) + unpack_line = fz_unpack_mono_line_unscaled_with_padding; + else if (n == 1 && depth == 1 && scale == 255 && pad && !skip) + unpack_line = fz_unpack_mono_line_scaled_with_padding; + else if (depth == 8 && !pad && !skip) + unpack_line = fz_unpack_line; + else if (depth == 8 && pad && !skip) + unpack_line = fz_unpack_line_with_padding; + else if (depth == 1 || depth == 2 || depth == 4 || depth == 8 || depth == 16 || depth == 24 || depth == 32) + unpack_line = fz_unpack_any_l2depth; + + if (unpack_line) + { + for (y = 0; y < h; y++, sp += stride, dp += dst->stride) + unpack_line(dp, sp, w, n, depth, scale, pad, skip); + } + else if (depth > 0 && depth <= 8 * (int)sizeof(int)) + { + fz_stream *stm; + int x, k; + size_t skipbits = 8 * stride - (size_t)w * n * depth; + + if (skipbits > 32) + fz_throw(ctx, FZ_ERROR_ARGUMENT, "Inappropriate stride!"); + + stm = fz_open_memory(ctx, sp, h * stride); + fz_try(ctx) + { + for (y = 0; y < h; y++) + { + for (x = 0; x < w; x++) + { + for (k = 0; k < n; k++) + { + if (depth <= 8) + *dp++ = fz_read_bits(ctx, stm, depth) << (8 - depth); + else + *dp++ = fz_read_bits(ctx, stm, depth) >> (depth - 8); + } + if (pad) + *dp++ = 255; + } + + dp += dst->stride - (size_t)w * (n + (pad > 0)); + (void) fz_read_bits(ctx, stm, (int)skipbits); + } + } + fz_always(ctx) + fz_drop_stream(ctx, stm); + fz_catch(ctx) + fz_rethrow(ctx); + } + else + fz_throw(ctx, FZ_ERROR_ARGUMENT, "cannot unpack tile with %d bits per component", depth); +} + +/* Apply decode array */ + +void +fz_decode_indexed_tile(fz_context *ctx, fz_pixmap *pix, const float *decode, int maxval) +{ + int add[FZ_MAX_COLORS]; + int mul[FZ_MAX_COLORS]; + unsigned char *p = pix->samples; + size_t stride = pix->stride - pix->w * (size_t)pix->n; + int len; + int pn = pix->n; + int n = pn - pix->alpha; + int needed; + int k; + int h; + + needed = 0; + for (k = 0; k < n; k++) + { + int min = decode[k * 2] * 256; + int max = decode[k * 2 + 1] * 256; + add[k] = min; + mul[k] = (max - min) / maxval; + needed |= min != 0 || max != maxval * 256; + } + + if (!needed) + return; + + h = pix->h; + while (h--) + { + len = pix->w; + while (len--) + { + for (k = 0; k < n; k++) + { + int value = (add[k] + (((p[k] << 8) * mul[k]) >> 8)) >> 8; + p[k] = fz_clampi(value, 0, 255); + } + p += pn; + } + p += stride; + } +} + +void +fz_decode_tile(fz_context *ctx, fz_pixmap *pix, const float *decode) +{ + int add[FZ_MAX_COLORS]; + int mul[FZ_MAX_COLORS]; + unsigned char *p = pix->samples; + size_t stride = pix->stride - pix->w * (size_t)pix->n; + int len; + int n = fz_maxi(1, pix->n - pix->alpha); + int k; + int h; + + for (k = 0; k < n; k++) + { + int min = decode[k * 2] * 255; + int max = decode[k * 2 + 1] * 255; + add[k] = min; + mul[k] = max - min; + } + + h = pix->h; + while (h--) + { + len = pix->w; + while (len--) + { + for (k = 0; k < n; k++) + { + int value = add[k] + fz_mul255(p[k], mul[k]); + p[k] = fz_clampi(value, 0, 255); + } + p += pix->n; + } + p += stride; + } +} + +typedef struct +{ + fz_stream *src; + int depth; + int w; + int h; + int n; + int skip; + int pad; + int scale; + int src_stride; + int dst_stride; + fz_unpack_line_fn unpack; + unsigned char buf[1]; +} unpack_state; + +static int +unpack_next(fz_context *ctx, fz_stream *stm, size_t max) +{ + unpack_state *state = (unpack_state *)stm->state; + size_t n = state->src_stride; + + stm->rp = state->buf; + do + { + size_t a = fz_available(ctx, state->src, n); + if (a == 0) + return EOF; + if (a > n) + a = n; + memcpy(stm->rp, state->src->rp, a); + stm->rp += a; + state->src->rp += a; + n -= a; + } + while (n); + + state->h--; + stm->pos += state->dst_stride; + stm->wp = stm->rp + state->dst_stride; + state->unpack(stm->rp, state->buf, state->w, state->n, state->depth, state->scale, state->pad, state->skip); + + return *stm->rp++; +} + +static void +unpack_drop(fz_context *ctx, void *state) +{ + fz_free(ctx, state); +} + +fz_stream * +fz_unpack_stream(fz_context *ctx, fz_stream *src, int depth, int w, int h, int n, int indexed, int pad, int skip) +{ + int src_stride = (w*depth*n+7)>>3; + int dst_stride; + unpack_state *state; + fz_unpack_line_fn unpack_line = NULL; + int scale = 1; + + if (depth == 1) + init_get1_tables(); + + if (!indexed) + switch (depth) + { + case 1: scale = 255; break; + case 2: scale = 85; break; + case 4: scale = 17; break; + } + + dst_stride = w * (n + !!pad); + + if (n == 1 && depth == 1 && scale == 1 && !pad && !skip) + unpack_line = fz_unpack_mono_line_unscaled; + else if (n == 1 && depth == 1 && scale == 255 && !pad && !skip) + unpack_line = fz_unpack_mono_line_scaled; + else if (n == 1 && depth == 1 && scale == 1 && pad && !skip) + unpack_line = fz_unpack_mono_line_unscaled_with_padding; + else if (n == 1 && depth == 1 && scale == 255 && pad && !skip) + unpack_line = fz_unpack_mono_line_scaled_with_padding; + else if (depth == 8 && !pad && !skip) + unpack_line = fz_unpack_line; + else if (depth == 8 && pad && !skip) + unpack_line = fz_unpack_line_with_padding; + else if (depth == 1 || depth == 2 || depth == 4 || depth == 8 || depth == 16 || depth == 24 || depth == 32) + unpack_line = fz_unpack_any_l2depth; + else + fz_throw(ctx, FZ_ERROR_ARGUMENT, "Unsupported combination in fz_unpack_stream"); + + state = fz_malloc(ctx, sizeof(unpack_state) + dst_stride + src_stride); + state->src = src; + state->depth = depth; + state->w = w; + state->h = h; + state->n = n; + state->skip = skip; + state->pad = pad; + state->scale = scale; + state->unpack = unpack_line; + state->src_stride = src_stride; + state->dst_stride = dst_stride; + + return fz_new_stream(ctx, state, unpack_next, unpack_drop); +}
