Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/source/fitz/draw-unpack.c @ 3:2c135c81b16c
MERGE: upstream PyMuPDF 1.26.4 with MuPDF 1.26.7
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:44:09 +0200 |
| parents | b50eed0cc0ef |
| children |
comparison
equal
deleted
inserted
replaced
| 0:6015a75abc2d | 3:2c135c81b16c |
|---|---|
| 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 #define get1(buf,x) ((buf[x >> 3] >> ( 7 - (x & 7) ) ) & 1 ) | |
| 31 #define get2(buf,x) ((buf[x >> 2] >> ( ( 3 - (x & 3) ) << 1 ) ) & 3 ) | |
| 32 #define get4(buf,x) ((buf[x >> 1] >> ( ( 1 - (x & 1) ) << 2 ) ) & 15 ) | |
| 33 #define get8(buf,x) (buf[x]) | |
| 34 #define get16(buf,x) (buf[x << 1]) | |
| 35 #define get24(buf,x) (buf[(x << 1) + x]) | |
| 36 #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 #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 { | |
| 65 static int once = 0; | |
| 66 unsigned char bits[1]; | |
| 67 int i, k, x; | |
| 68 | |
| 69 /* TODO: mutex lock here */ | |
| 70 | |
| 71 if (once) | |
| 72 return; | |
| 73 | |
| 74 for (i = 0; i < 256; i++) | |
| 75 { | |
| 76 bits[0] = i; | |
| 77 for (k = 0; k < 8; k++) | |
| 78 { | |
| 79 x = get1(bits, k); | |
| 80 | |
| 81 get1_tab_1[i][k] = x; | |
| 82 get1_tab_1p[i][k * 2] = x; | |
| 83 get1_tab_1p[i][k * 2 + 1] = 255; | |
| 84 | |
| 85 get1_tab_255[i][k] = x * 255; | |
| 86 get1_tab_255p[i][k * 2] = x * 255; | |
| 87 get1_tab_255p[i][k * 2 + 1] = 255; | |
| 88 } | |
| 89 } | |
| 90 | |
| 91 once = 1; | |
| 92 } | |
| 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 { | |
| 97 int w3 = w >> 3; | |
| 98 int x; | |
| 99 | |
| 100 for (x = 0; x < w3; x++) | |
| 101 { | |
| 102 memcpy(dp, get1_tab_1[*sp++], 8); | |
| 103 dp += 8; | |
| 104 } | |
| 105 x = x << 3; | |
| 106 if (x < w) | |
| 107 memcpy(dp, get1_tab_1[VGMASK(*sp, w - x)], w - x); | |
| 108 } | |
| 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 { | |
| 113 int w3 = w >> 3; | |
| 114 int x; | |
| 115 | |
| 116 for (x = 0; x < w3; x++) | |
| 117 { | |
| 118 memcpy(dp, get1_tab_255[*sp++], 8); | |
| 119 dp += 8; | |
| 120 } | |
| 121 x = x << 3; | |
| 122 if (x < w) | |
| 123 memcpy(dp, get1_tab_255[VGMASK(*sp, w - x)], w - x); | |
| 124 } | |
| 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 { | |
| 129 int w3 = w >> 3; | |
| 130 int x; | |
| 131 | |
| 132 for (x = 0; x < w3; x++) | |
| 133 { | |
| 134 memcpy(dp, get1_tab_1p[*sp++], 16); | |
| 135 dp += 16; | |
| 136 } | |
| 137 x = x << 3; | |
| 138 if (x < w) | |
| 139 memcpy(dp, get1_tab_1p[VGMASK(*sp, w - x)], (w - x) << 1); | |
| 140 } | |
| 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 { | |
| 145 int w3 = w >> 3; | |
| 146 int x; | |
| 147 | |
| 148 for (x = 0; x < w3; x++) | |
| 149 { | |
| 150 memcpy(dp, get1_tab_255p[*sp++], 16); | |
| 151 dp += 16; | |
| 152 } | |
| 153 x = x << 3; | |
| 154 if (x < w) | |
| 155 memcpy(dp, get1_tab_255p[VGMASK(*sp, w - x)], (w - x) << 1); | |
| 156 } | |
| 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 { | |
| 161 int len = w * n; | |
| 162 while (len--) | |
| 163 *dp++ = *sp++; | |
| 164 } | |
| 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 { | |
| 169 int x, k; | |
| 170 | |
| 171 for (x = 0; x < w; x++) | |
| 172 { | |
| 173 for (k = 0; k < n; k++) | |
| 174 *dp++ = *sp++; | |
| 175 *dp++ = 255; | |
| 176 } | |
| 177 } | |
| 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 { | |
| 182 unsigned char *p = dp; | |
| 183 int b = 0; | |
| 184 int x, k; | |
| 185 | |
| 186 for (x = 0; x < w; x++) | |
| 187 { | |
| 188 for (k = 0; k < n; k++) | |
| 189 { | |
| 190 switch (depth) | |
| 191 { | |
| 192 case 1: *p++ = get1(sp, b) * scale; break; | |
| 193 case 2: *p++ = get2(sp, b) * scale; break; | |
| 194 case 4: *p++ = get4(sp, b) * scale; break; | |
| 195 case 8: *p++ = get8(sp, b); break; | |
| 196 case 16: *p++ = get16(sp, b); break; | |
| 197 case 24: *p++ = get24(sp, b); break; | |
| 198 case 32: *p++ = get32(sp, b); break; | |
| 199 } | |
| 200 b++; | |
| 201 } | |
| 202 b += skip; | |
| 203 if (pad) | |
| 204 *p++ = 255; | |
| 205 } | |
| 206 } | |
| 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 { | |
| 213 unsigned char *sp = src; | |
| 214 unsigned char *dp = dst->samples; | |
| 215 fz_unpack_line_fn unpack_line = NULL; | |
| 216 int pad, y, skip; | |
| 217 int w = dst->w; | |
| 218 int h = dst->h; | |
| 219 | |
| 220 pad = 0; | |
| 221 skip = 0; | |
| 222 if (dst->n > n) | |
| 223 pad = 255; | |
| 224 if (dst->n < n) | |
| 225 { | |
| 226 skip = n - dst->n; | |
| 227 n = dst->n; | |
| 228 } | |
| 229 | |
| 230 if (depth == 1) | |
| 231 init_get1_tables(); | |
| 232 | |
| 233 if (scale == 0) | |
| 234 { | |
| 235 switch (depth) | |
| 236 { | |
| 237 case 1: scale = 255; break; | |
| 238 case 2: scale = 85; break; | |
| 239 case 4: scale = 17; break; | |
| 240 } | |
| 241 } | |
| 242 | |
| 243 if (n == 1 && depth == 1 && scale == 1 && !pad && !skip) | |
| 244 unpack_line = fz_unpack_mono_line_unscaled; | |
| 245 else if (n == 1 && depth == 1 && scale == 255 && !pad && !skip) | |
| 246 unpack_line = fz_unpack_mono_line_scaled; | |
| 247 else if (n == 1 && depth == 1 && scale == 1 && pad && !skip) | |
| 248 unpack_line = fz_unpack_mono_line_unscaled_with_padding; | |
| 249 else if (n == 1 && depth == 1 && scale == 255 && pad && !skip) | |
| 250 unpack_line = fz_unpack_mono_line_scaled_with_padding; | |
| 251 else if (depth == 8 && !pad && !skip) | |
| 252 unpack_line = fz_unpack_line; | |
| 253 else if (depth == 8 && pad && !skip) | |
| 254 unpack_line = fz_unpack_line_with_padding; | |
| 255 else if (depth == 1 || depth == 2 || depth == 4 || depth == 8 || depth == 16 || depth == 24 || depth == 32) | |
| 256 unpack_line = fz_unpack_any_l2depth; | |
| 257 | |
| 258 if (unpack_line) | |
| 259 { | |
| 260 for (y = 0; y < h; y++, sp += stride, dp += dst->stride) | |
| 261 unpack_line(dp, sp, w, n, depth, scale, pad, skip); | |
| 262 } | |
| 263 else if (depth > 0 && depth <= 8 * (int)sizeof(int)) | |
| 264 { | |
| 265 fz_stream *stm; | |
| 266 int x, k; | |
| 267 size_t skipbits = 8 * stride - (size_t)w * n * depth; | |
| 268 | |
| 269 if (skipbits > 32) | |
| 270 fz_throw(ctx, FZ_ERROR_ARGUMENT, "Inappropriate stride!"); | |
| 271 | |
| 272 stm = fz_open_memory(ctx, sp, h * stride); | |
| 273 fz_try(ctx) | |
| 274 { | |
| 275 for (y = 0; y < h; y++) | |
| 276 { | |
| 277 for (x = 0; x < w; x++) | |
| 278 { | |
| 279 for (k = 0; k < n; k++) | |
| 280 { | |
| 281 if (depth <= 8) | |
| 282 *dp++ = fz_read_bits(ctx, stm, depth) << (8 - depth); | |
| 283 else | |
| 284 *dp++ = fz_read_bits(ctx, stm, depth) >> (depth - 8); | |
| 285 } | |
| 286 if (pad) | |
| 287 *dp++ = 255; | |
| 288 } | |
| 289 | |
| 290 dp += dst->stride - (size_t)w * (n + (pad > 0)); | |
| 291 (void) fz_read_bits(ctx, stm, (int)skipbits); | |
| 292 } | |
| 293 } | |
| 294 fz_always(ctx) | |
| 295 fz_drop_stream(ctx, stm); | |
| 296 fz_catch(ctx) | |
| 297 fz_rethrow(ctx); | |
| 298 } | |
| 299 else | |
| 300 fz_throw(ctx, FZ_ERROR_ARGUMENT, "cannot unpack tile with %d bits per component", depth); | |
| 301 } | |
| 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 { | |
| 308 int add[FZ_MAX_COLORS]; | |
| 309 int mul[FZ_MAX_COLORS]; | |
| 310 unsigned char *p = pix->samples; | |
| 311 size_t stride = pix->stride - pix->w * (size_t)pix->n; | |
| 312 int len; | |
| 313 int pn = pix->n; | |
| 314 int n = pn - pix->alpha; | |
| 315 int needed; | |
| 316 int k; | |
| 317 int h; | |
| 318 | |
| 319 needed = 0; | |
| 320 for (k = 0; k < n; k++) | |
| 321 { | |
| 322 int min = decode[k * 2] * 256; | |
| 323 int max = decode[k * 2 + 1] * 256; | |
| 324 add[k] = min; | |
| 325 mul[k] = (max - min) / maxval; | |
| 326 needed |= min != 0 || max != maxval * 256; | |
| 327 } | |
| 328 | |
| 329 if (!needed) | |
| 330 return; | |
| 331 | |
| 332 h = pix->h; | |
| 333 while (h--) | |
| 334 { | |
| 335 len = pix->w; | |
| 336 while (len--) | |
| 337 { | |
| 338 for (k = 0; k < n; k++) | |
| 339 { | |
| 340 int value = (add[k] + (((p[k] << 8) * mul[k]) >> 8)) >> 8; | |
| 341 p[k] = fz_clampi(value, 0, 255); | |
| 342 } | |
| 343 p += pn; | |
| 344 } | |
| 345 p += stride; | |
| 346 } | |
| 347 } | |
| 348 | |
| 349 void | |
| 350 fz_decode_tile(fz_context *ctx, fz_pixmap *pix, const float *decode) | |
| 351 { | |
| 352 int add[FZ_MAX_COLORS]; | |
| 353 int mul[FZ_MAX_COLORS]; | |
| 354 unsigned char *p = pix->samples; | |
| 355 size_t stride = pix->stride - pix->w * (size_t)pix->n; | |
| 356 int len; | |
| 357 int n = fz_maxi(1, pix->n - pix->alpha); | |
| 358 int k; | |
| 359 int h; | |
| 360 | |
| 361 for (k = 0; k < n; k++) | |
| 362 { | |
| 363 int min = decode[k * 2] * 255; | |
| 364 int max = decode[k * 2 + 1] * 255; | |
| 365 add[k] = min; | |
| 366 mul[k] = max - min; | |
| 367 } | |
| 368 | |
| 369 h = pix->h; | |
| 370 while (h--) | |
| 371 { | |
| 372 len = pix->w; | |
| 373 while (len--) | |
| 374 { | |
| 375 for (k = 0; k < n; k++) | |
| 376 { | |
| 377 int value = add[k] + fz_mul255(p[k], mul[k]); | |
| 378 p[k] = fz_clampi(value, 0, 255); | |
| 379 } | |
| 380 p += pix->n; | |
| 381 } | |
| 382 p += stride; | |
| 383 } | |
| 384 } | |
| 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 int src_stride; | |
| 397 int 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 { | |
| 405 unpack_state *state = (unpack_state *)stm->state; | |
| 406 size_t n = state->src_stride; | |
| 407 | |
| 408 stm->rp = state->buf; | |
| 409 do | |
| 410 { | |
| 411 size_t a = fz_available(ctx, state->src, n); | |
| 412 if (a == 0) | |
| 413 return EOF; | |
| 414 if (a > n) | |
| 415 a = n; | |
| 416 memcpy(stm->rp, state->src->rp, a); | |
| 417 stm->rp += a; | |
| 418 state->src->rp += a; | |
| 419 n -= a; | |
| 420 } | |
| 421 while (n); | |
| 422 | |
| 423 state->h--; | |
| 424 stm->pos += state->dst_stride; | |
| 425 stm->wp = stm->rp + state->dst_stride; | |
| 426 state->unpack(stm->rp, state->buf, state->w, state->n, state->depth, state->scale, state->pad, state->skip); | |
| 427 | |
| 428 return *stm->rp++; | |
| 429 } | |
| 430 | |
| 431 static void | |
| 432 unpack_drop(fz_context *ctx, void *state) | |
| 433 { | |
| 434 fz_free(ctx, state); | |
| 435 } | |
| 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 { | |
| 440 int src_stride = (w*depth*n+7)>>3; | |
| 441 int dst_stride; | |
| 442 unpack_state *state; | |
| 443 fz_unpack_line_fn unpack_line = NULL; | |
| 444 int scale = 1; | |
| 445 | |
| 446 if (depth == 1) | |
| 447 init_get1_tables(); | |
| 448 | |
| 449 if (!indexed) | |
| 450 switch (depth) | |
| 451 { | |
| 452 case 1: scale = 255; break; | |
| 453 case 2: scale = 85; break; | |
| 454 case 4: scale = 17; break; | |
| 455 } | |
| 456 | |
| 457 dst_stride = w * (n + !!pad); | |
| 458 | |
| 459 if (n == 1 && depth == 1 && scale == 1 && !pad && !skip) | |
| 460 unpack_line = fz_unpack_mono_line_unscaled; | |
| 461 else if (n == 1 && depth == 1 && scale == 255 && !pad && !skip) | |
| 462 unpack_line = fz_unpack_mono_line_scaled; | |
| 463 else if (n == 1 && depth == 1 && scale == 1 && pad && !skip) | |
| 464 unpack_line = fz_unpack_mono_line_unscaled_with_padding; | |
| 465 else if (n == 1 && depth == 1 && scale == 255 && pad && !skip) | |
| 466 unpack_line = fz_unpack_mono_line_scaled_with_padding; | |
| 467 else if (depth == 8 && !pad && !skip) | |
| 468 unpack_line = fz_unpack_line; | |
| 469 else if (depth == 8 && pad && !skip) | |
| 470 unpack_line = fz_unpack_line_with_padding; | |
| 471 else if (depth == 1 || depth == 2 || depth == 4 || depth == 8 || depth == 16 || depth == 24 || depth == 32) | |
| 472 unpack_line = fz_unpack_any_l2depth; | |
| 473 else | |
| 474 fz_throw(ctx, FZ_ERROR_ARGUMENT, "Unsupported combination in fz_unpack_stream"); | |
| 475 | |
| 476 state = fz_malloc(ctx, sizeof(unpack_state) + dst_stride + src_stride); | |
| 477 state->src = src; | |
| 478 state->depth = depth; | |
| 479 state->w = w; | |
| 480 state->h = h; | |
| 481 state->n = n; | |
| 482 state->skip = skip; | |
| 483 state->pad = pad; | |
| 484 state->scale = scale; | |
| 485 state->unpack = unpack_line; | |
| 486 state->src_stride = src_stride; | |
| 487 state->dst_stride = dst_stride; | |
| 488 | |
| 489 return fz_new_stream(ctx, state, unpack_next, unpack_drop); | |
| 490 } |
