Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/source/fitz/load-jpx.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 |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 1 // Copyright (C) 2004-2023 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 | |
| 25 #include "pixmap-imp.h" | |
| 26 | |
| 27 #include <assert.h> | |
| 28 #include <string.h> | |
| 29 | |
| 30 #if FZ_ENABLE_JPX | |
| 31 | |
| 32 static void | |
| 33 jpx_ycc_to_rgb(fz_context *ctx, fz_pixmap *pix, int cbsign, int crsign) | |
| 34 { | |
| 35 int w = pix->w; | |
| 36 int h = pix->h; | |
| 37 int stride = pix->stride; | |
| 38 int x, y; | |
| 39 | |
| 40 for (y = 0; y < h; y++) | |
| 41 { | |
| 42 unsigned char * row = &pix->samples[stride * y]; | |
| 43 for (x = 0; x < w; x++) | |
| 44 { | |
| 45 int ycc[3]; | |
| 46 ycc[0] = row[x * 3 + 0]; | |
| 47 ycc[1] = row[x * 3 + 1]; | |
| 48 ycc[2] = row[x * 3 + 2]; | |
| 49 | |
| 50 /* consciously skip Y */ | |
| 51 if (cbsign) | |
| 52 ycc[1] -= 128; | |
| 53 if (crsign) | |
| 54 ycc[2] -= 128; | |
| 55 | |
| 56 row[x * 3 + 0] = fz_clampi(ycc[0] + 1.402f * ycc[2], 0, 255); | |
| 57 row[x * 3 + 1] = fz_clampi(ycc[0] - 0.34413f * ycc[1] - 0.71414f * ycc[2], 0, 255); | |
| 58 row[x * 3 + 2] = fz_clampi(ycc[0] + 1.772f * ycc[1], 0, 255); | |
| 59 } | |
| 60 } | |
| 61 } | |
| 62 | |
| 63 #include <openjpeg.h> | |
| 64 | |
| 65 typedef struct | |
| 66 { | |
| 67 int width; | |
| 68 int height; | |
| 69 fz_colorspace *cs; | |
| 70 int xres; | |
| 71 int yres; | |
| 72 } fz_jpxd; | |
| 73 | |
| 74 typedef struct | |
| 75 { | |
| 76 const unsigned char *data; | |
| 77 OPJ_SIZE_T size; | |
| 78 OPJ_SIZE_T pos; | |
| 79 } stream_block; | |
| 80 | |
| 81 /* OpenJPEG does not provide a safe mechanism to intercept | |
| 82 * allocations. In the latest version all allocations go | |
| 83 * though opj_malloc etc, but no context is passed around. | |
| 84 * | |
| 85 * In order to ensure that allocations throughout mupdf | |
| 86 * are done consistently, we implement opj_malloc etc as | |
| 87 * functions that call down to fz_malloc etc. These | |
| 88 * require context variables, so we lock and unlock around | |
| 89 * calls to openjpeg. Any attempt to call through | |
| 90 * without setting these will be detected. | |
| 91 * | |
| 92 * It is therefore vital that any fz_lock/fz_unlock | |
| 93 * handlers are shared between all the fz_contexts in | |
| 94 * use at a time. | |
| 95 */ | |
| 96 | |
| 97 /* Potentially we can write different versions | |
| 98 * of get_context and set_context for different | |
| 99 * threading systems. | |
| 100 */ | |
| 101 | |
| 102 static fz_context *opj_secret = NULL; | |
| 103 | |
| 104 static void set_opj_context(fz_context *ctx) | |
| 105 { | |
| 106 opj_secret = ctx; | |
| 107 } | |
| 108 | |
| 109 static fz_context *get_opj_context(void) | |
| 110 { | |
| 111 return opj_secret; | |
| 112 } | |
| 113 | |
| 114 void opj_lock(fz_context *ctx) | |
| 115 { | |
| 116 fz_ft_lock(ctx); | |
| 117 | |
| 118 set_opj_context(ctx); | |
| 119 } | |
| 120 | |
| 121 void opj_unlock(fz_context *ctx) | |
| 122 { | |
| 123 set_opj_context(NULL); | |
| 124 | |
| 125 fz_ft_unlock(ctx); | |
| 126 } | |
| 127 | |
| 128 void *opj_malloc(size_t size) | |
| 129 { | |
| 130 fz_context *ctx = get_opj_context(); | |
| 131 | |
| 132 assert(ctx != NULL); | |
| 133 | |
| 134 return Memento_label(fz_malloc_no_throw(ctx, size), "opj_malloc"); | |
| 135 } | |
| 136 | |
| 137 void *opj_calloc(size_t n, size_t size) | |
| 138 { | |
| 139 fz_context *ctx = get_opj_context(); | |
| 140 | |
| 141 assert(ctx != NULL); | |
| 142 | |
| 143 return fz_calloc_no_throw(ctx, n, size); | |
| 144 } | |
| 145 | |
| 146 void *opj_realloc(void *ptr, size_t size) | |
| 147 { | |
| 148 fz_context *ctx = get_opj_context(); | |
| 149 | |
| 150 assert(ctx != NULL); | |
| 151 | |
| 152 return fz_realloc_no_throw(ctx, ptr, size); | |
| 153 } | |
| 154 | |
| 155 void opj_free(void *ptr) | |
| 156 { | |
| 157 fz_context *ctx = get_opj_context(); | |
| 158 | |
| 159 assert(ctx != NULL); | |
| 160 | |
| 161 fz_free(ctx, ptr); | |
| 162 } | |
| 163 | |
| 164 static void * opj_aligned_malloc_n(size_t alignment, size_t size) | |
| 165 { | |
| 166 uint8_t *ptr; | |
| 167 size_t off; | |
| 168 | |
| 169 if (size == 0) | |
| 170 return NULL; | |
| 171 | |
| 172 size += alignment + sizeof(uint8_t); | |
| 173 ptr = opj_malloc(size); | |
| 174 if (ptr == NULL) | |
| 175 return NULL; | |
| 176 off = alignment-(((int)(intptr_t)ptr) & (alignment - 1)); | |
| 177 ptr[off-1] = (uint8_t)off; | |
| 178 return ptr + off; | |
| 179 } | |
| 180 | |
| 181 void * opj_aligned_malloc(size_t size) | |
| 182 { | |
| 183 return opj_aligned_malloc_n(16, size); | |
| 184 } | |
| 185 | |
| 186 void * opj_aligned_32_malloc(size_t size) | |
| 187 { | |
| 188 return opj_aligned_malloc_n(32, size); | |
| 189 } | |
| 190 | |
| 191 void opj_aligned_free(void* ptr_) | |
| 192 { | |
| 193 uint8_t *ptr = (uint8_t *)ptr_; | |
| 194 uint8_t off; | |
| 195 if (ptr == NULL) | |
| 196 return; | |
| 197 | |
| 198 off = ptr[-1]; | |
| 199 opj_free((void *)(((unsigned char *)ptr) - off)); | |
| 200 } | |
| 201 | |
| 202 #if 0 | |
| 203 /* UNUSED currently, and moderately tricky, so deferred until required */ | |
| 204 void * opj_aligned_realloc(void *ptr, size_t size) | |
| 205 { | |
| 206 return opj_realloc(ptr, size); | |
| 207 } | |
| 208 #endif | |
| 209 | |
| 210 static void fz_opj_error_callback(const char *msg, void *client_data) | |
| 211 { | |
| 212 fz_context *ctx = (fz_context *)client_data; | |
| 213 char buf[200]; | |
| 214 size_t n; | |
| 215 fz_strlcpy(buf, msg, sizeof buf); | |
| 216 n = strlen(buf); | |
| 217 if (buf[n-1] == '\n') | |
| 218 buf[n-1] = 0; | |
| 219 fz_warn(ctx, "openjpeg error: %s", buf); | |
| 220 } | |
| 221 | |
| 222 static void fz_opj_warning_callback(const char *msg, void *client_data) | |
| 223 { | |
| 224 fz_context *ctx = (fz_context *)client_data; | |
| 225 char buf[200]; | |
| 226 size_t n; | |
| 227 fz_strlcpy(buf, msg, sizeof buf); | |
| 228 n = strlen(buf); | |
| 229 if (buf[n-1] == '\n') | |
| 230 buf[n-1] = 0; | |
| 231 fz_warn(ctx, "openjpeg warning: %s", buf); | |
| 232 } | |
| 233 | |
| 234 static void fz_opj_info_callback(const char *msg, void *client_data) | |
| 235 { | |
| 236 /* fz_warn("openjpeg info: %s", msg); */ | |
| 237 } | |
| 238 | |
| 239 static OPJ_SIZE_T fz_opj_stream_read(void * p_buffer, OPJ_SIZE_T p_nb_bytes, void * p_user_data) | |
| 240 { | |
| 241 stream_block *sb = (stream_block *)p_user_data; | |
| 242 OPJ_SIZE_T len; | |
| 243 | |
| 244 len = sb->size - sb->pos; | |
| 245 if (len == 0) | |
| 246 return (OPJ_SIZE_T)-1; /* End of file! */ | |
| 247 if (len > p_nb_bytes) | |
| 248 len = p_nb_bytes; | |
| 249 memcpy(p_buffer, sb->data + sb->pos, len); | |
| 250 sb->pos += len; | |
| 251 return len; | |
| 252 } | |
| 253 | |
| 254 static OPJ_OFF_T fz_opj_stream_skip(OPJ_OFF_T skip, void * p_user_data) | |
| 255 { | |
| 256 stream_block *sb = (stream_block *)p_user_data; | |
| 257 | |
| 258 if (skip > (OPJ_OFF_T)(sb->size - sb->pos)) | |
| 259 skip = (OPJ_OFF_T)(sb->size - sb->pos); | |
| 260 sb->pos += skip; | |
| 261 return sb->pos; | |
| 262 } | |
| 263 | |
| 264 static OPJ_BOOL fz_opj_stream_seek(OPJ_OFF_T seek_pos, void * p_user_data) | |
| 265 { | |
| 266 stream_block *sb = (stream_block *)p_user_data; | |
| 267 | |
| 268 if (seek_pos > (OPJ_OFF_T)sb->size) | |
| 269 return OPJ_FALSE; | |
| 270 sb->pos = seek_pos; | |
| 271 return OPJ_TRUE; | |
| 272 } | |
| 273 | |
| 274 static int32_t | |
| 275 safe_mul32(fz_context *ctx, int32_t a, int32_t b) | |
| 276 { | |
| 277 int64_t res = ((int64_t)a) * b; | |
| 278 int32_t res32 = (int32_t)res; | |
| 279 | |
| 280 if ((res32) != res) | |
| 281 fz_throw(ctx, FZ_ERROR_LIMIT, "Overflow while decoding jpx"); | |
| 282 return res32; | |
| 283 } | |
| 284 | |
| 285 static int32_t | |
| 286 safe_mla32(fz_context *ctx, int32_t a, int32_t b, int32_t c) | |
| 287 { | |
| 288 int64_t res = ((int64_t)a) * b + c; | |
| 289 int32_t res32 = (int32_t)res; | |
| 290 | |
| 291 if ((res32) != res) | |
| 292 fz_throw(ctx, FZ_ERROR_LIMIT, "Overflow while decoding jpx"); | |
| 293 return res32; | |
| 294 } | |
| 295 | |
| 296 static inline void | |
| 297 template_copy_comp(unsigned char *dst0, int w, int h, int stride, const OPJ_INT32 *src, int32_t ox, int32_t oy, OPJ_UINT32 cdx, OPJ_UINT32 cdy, OPJ_UINT32 cw, OPJ_UINT32 ch, OPJ_UINT32 sgnd, OPJ_UINT32 prec, int comps) | |
| 298 { | |
| 299 int x, y; | |
| 300 | |
| 301 for (y = ch; oy + cdy <= 0 && y > 0; y--) | |
| 302 { | |
| 303 oy += cdy; | |
| 304 dst0 += cdy * stride; | |
| 305 src += cw; | |
| 306 } | |
| 307 for (; y > 0; y--) | |
| 308 { | |
| 309 int32_t dymin = oy; | |
| 310 int32_t dywid = cdy; | |
| 311 unsigned char *dst1 = dst0 + ox * comps; | |
| 312 int32_t oox = ox; | |
| 313 const OPJ_INT32 *src0 = src; | |
| 314 | |
| 315 if (dymin < 0) | |
| 316 dywid += dymin, dst1 -= dymin * stride, dymin = 0; | |
| 317 if (dymin >= h) | |
| 318 break; | |
| 319 if (dymin + dywid > h) | |
| 320 dywid = h - dymin; | |
| 321 | |
| 322 for (x = cw; oox + cdx <= 0 && x > 0; x--) | |
| 323 { | |
| 324 oox += cdx; | |
| 325 dst1 += cdx * comps; | |
| 326 src0++; | |
| 327 } | |
| 328 for (; x > 0; x--) | |
| 329 { | |
| 330 OPJ_INT32 v; | |
| 331 int32_t xx, yy; | |
| 332 int32_t dxmin = oox; | |
| 333 int32_t dxwid = cdx; | |
| 334 unsigned char *dst2; | |
| 335 | |
| 336 v = *src0++; | |
| 337 | |
| 338 if (sgnd) | |
| 339 v = v + (1 << (prec - 1)); | |
| 340 if (prec > 8) | |
| 341 v = v >> (prec - 8); | |
| 342 else if (prec < 8) | |
| 343 v = v << (8 - prec); | |
| 344 | |
| 345 if (dxmin < 0) | |
| 346 dxwid += dxmin, dst1 -= dxmin * comps, dxmin = 0; | |
| 347 if (dxmin >= w) | |
| 348 break; | |
| 349 if (dxmin + dxwid > w) | |
| 350 dxwid = w - dxmin; | |
| 351 | |
| 352 dst2 = dst1; | |
| 353 for (yy = dywid; yy > 0; yy--) | |
| 354 { | |
| 355 unsigned char *dst3 = dst2; | |
| 356 for (xx = dxwid; xx > 0; xx--) | |
| 357 { | |
| 358 *dst3 = v; | |
| 359 dst3 += comps; | |
| 360 } | |
| 361 dst2 += stride; | |
| 362 } | |
| 363 dst1 += comps * cdx; | |
| 364 oox += cdx; | |
| 365 } | |
| 366 dst0 += stride * cdy; | |
| 367 src += cw; | |
| 368 oy += cdy; | |
| 369 } | |
| 370 } | |
| 371 | |
| 372 static void | |
| 373 copy_jpx_to_pixmap(fz_context *ctx, fz_pixmap *img, opj_image_t *jpx) | |
| 374 { | |
| 375 unsigned char *dst; | |
| 376 int stride, comps; | |
| 377 int w = img->w; | |
| 378 int h = img->h; | |
| 379 int k; | |
| 380 | |
| 381 stride = fz_pixmap_stride(ctx, img); | |
| 382 comps = fz_pixmap_components(ctx, img); | |
| 383 dst = fz_pixmap_samples(ctx, img); | |
| 384 | |
| 385 for (k = 0; k < comps; k++) | |
| 386 { | |
| 387 opj_image_comp_t *comp = &(jpx->comps[k]); | |
| 388 OPJ_UINT32 cdx = comp->dx; | |
| 389 OPJ_UINT32 cdy = comp->dy; | |
| 390 OPJ_UINT32 cw = comp->w; | |
| 391 OPJ_UINT32 ch = comp->h; | |
| 392 int32_t oy = safe_mul32(ctx, comp->y0, cdy) - jpx->y0; | |
| 393 int32_t ox = safe_mul32(ctx, comp->x0, cdx) - jpx->x0; | |
| 394 unsigned char *dst0 = dst + oy * stride; | |
| 395 int prec = comp->prec; | |
| 396 int sgnd = comp->sgnd; | |
| 397 | |
| 398 if (comp->data == NULL) | |
| 399 fz_throw(ctx, FZ_ERROR_FORMAT, "No data for JP2 image component %d", k); | |
| 400 | |
| 401 if (fz_colorspace_is_indexed(ctx, img->colorspace)) | |
| 402 { | |
| 403 prec = 8; /* Don't do any scaling! */ | |
| 404 sgnd = 0; | |
| 405 } | |
| 406 | |
| 407 /* Check that none of the following will overflow. */ | |
| 408 (void)safe_mla32(ctx, ch, cdy, oy); | |
| 409 (void)safe_mla32(ctx, cw, cdx, ox); | |
| 410 | |
| 411 if (cdx == 1 && cdy == 1) | |
| 412 template_copy_comp(dst0, w, h, stride, comp->data, ox, oy, 1 /*cdx*/, 1 /*cdy*/, cw, ch, sgnd, prec, comps); | |
| 413 else | |
| 414 template_copy_comp(dst0, w, h, stride, comp->data, ox, oy, cdx, cdy, cw, ch, sgnd, prec, comps); | |
| 415 dst++; | |
| 416 } | |
| 417 } | |
| 418 | |
| 419 static fz_pixmap * | |
| 420 jpx_read_image(fz_context *ctx, fz_jpxd *state, const unsigned char *data, size_t size, fz_colorspace *defcs, int onlymeta) | |
| 421 { | |
| 422 fz_pixmap *img = NULL; | |
| 423 opj_dparameters_t params; | |
| 424 opj_codec_t *codec; | |
| 425 opj_image_t *jpx; | |
| 426 opj_stream_t *stream; | |
| 427 OPJ_CODEC_FORMAT format; | |
| 428 int a, n, k; | |
| 429 int w, h; | |
| 430 stream_block sb; | |
| 431 OPJ_UINT32 i; | |
| 432 | |
| 433 fz_var(img); | |
| 434 | |
| 435 if (size < 2) | |
| 436 fz_throw(ctx, FZ_ERROR_FORMAT, "not enough data to determine image format"); | |
| 437 | |
| 438 /* Check for SOC marker -- if found we have a bare J2K stream */ | |
| 439 if (data[0] == 0xFF && data[1] == 0x4F) | |
| 440 format = OPJ_CODEC_J2K; | |
| 441 else | |
| 442 format = OPJ_CODEC_JP2; | |
| 443 | |
| 444 opj_set_default_decoder_parameters(¶ms); | |
| 445 if (fz_colorspace_is_indexed(ctx, defcs)) | |
| 446 params.flags |= OPJ_DPARAMETERS_IGNORE_PCLR_CMAP_CDEF_FLAG; | |
| 447 | |
| 448 codec = opj_create_decompress(format); | |
| 449 opj_set_info_handler(codec, fz_opj_info_callback, ctx); | |
| 450 opj_set_warning_handler(codec, fz_opj_warning_callback, ctx); | |
| 451 opj_set_error_handler(codec, fz_opj_error_callback, ctx); | |
| 452 if (!opj_setup_decoder(codec, ¶ms)) | |
| 453 { | |
| 454 opj_destroy_codec(codec); | |
| 455 fz_throw(ctx, FZ_ERROR_LIBRARY, "j2k decode failed"); | |
| 456 } | |
| 457 | |
| 458 stream = opj_stream_default_create(OPJ_TRUE); | |
| 459 sb.data = data; | |
| 460 sb.pos = 0; | |
| 461 sb.size = size; | |
| 462 | |
| 463 opj_stream_set_read_function(stream, fz_opj_stream_read); | |
| 464 opj_stream_set_skip_function(stream, fz_opj_stream_skip); | |
| 465 opj_stream_set_seek_function(stream, fz_opj_stream_seek); | |
| 466 opj_stream_set_user_data(stream, &sb, NULL); | |
| 467 /* Set the length to avoid an assert */ | |
| 468 opj_stream_set_user_data_length(stream, size); | |
| 469 | |
| 470 if (!opj_read_header(stream, codec, &jpx)) | |
| 471 { | |
| 472 opj_stream_destroy(stream); | |
| 473 opj_destroy_codec(codec); | |
| 474 fz_throw(ctx, FZ_ERROR_LIBRARY, "Failed to read JPX header"); | |
| 475 } | |
| 476 | |
| 477 if (!opj_decode(codec, stream, jpx)) | |
| 478 { | |
| 479 opj_stream_destroy(stream); | |
| 480 opj_destroy_codec(codec); | |
| 481 opj_image_destroy(jpx); | |
| 482 fz_throw(ctx, FZ_ERROR_LIBRARY, "Failed to decode JPX image"); | |
| 483 } | |
| 484 | |
| 485 opj_stream_destroy(stream); | |
| 486 opj_destroy_codec(codec); | |
| 487 | |
| 488 /* jpx should never be NULL here, but check anyway */ | |
| 489 if (!jpx) | |
| 490 fz_throw(ctx, FZ_ERROR_LIBRARY, "opj_decode failed"); | |
| 491 | |
| 492 /* Count number of alpha and color channels */ | |
| 493 n = a = 0; | |
| 494 for (i = 0; i < jpx->numcomps; ++i) | |
| 495 { | |
| 496 if (jpx->comps[i].alpha) | |
| 497 ++a; | |
| 498 else | |
| 499 ++n; | |
| 500 } | |
| 501 | |
| 502 for (k = 1; k < n + a; k++) | |
| 503 { | |
| 504 if (!jpx->comps[k].data) | |
| 505 { | |
| 506 opj_image_destroy(jpx); | |
| 507 fz_throw(ctx, FZ_ERROR_FORMAT, "image components are missing data"); | |
| 508 } | |
| 509 } | |
| 510 | |
| 511 w = state->width = jpx->x1 - jpx->x0; | |
| 512 h = state->height = jpx->y1 - jpx->y0; | |
| 513 state->xres = 72; /* openjpeg does not read the JPEG 2000 resc box */ | |
| 514 state->yres = 72; /* openjpeg does not read the JPEG 2000 resc box */ | |
| 515 | |
| 516 if (w < 0 || h < 0) | |
| 517 { | |
| 518 opj_image_destroy(jpx); | |
| 519 fz_throw(ctx, FZ_ERROR_LIMIT, "Unbelievable size for jpx"); | |
| 520 } | |
| 521 | |
| 522 state->cs = NULL; | |
| 523 | |
| 524 if (defcs) | |
| 525 { | |
| 526 if (defcs->n == n) | |
| 527 state->cs = fz_keep_colorspace(ctx, defcs); | |
| 528 else | |
| 529 fz_warn(ctx, "jpx file and dict colorspace do not match"); | |
| 530 } | |
| 531 | |
| 532 #if FZ_ENABLE_ICC | |
| 533 if (!state->cs && jpx->icc_profile_buf && jpx->icc_profile_len > 0) | |
| 534 { | |
| 535 fz_buffer *cbuf = NULL; | |
| 536 fz_var(cbuf); | |
| 537 | |
| 538 fz_try(ctx) | |
| 539 { | |
| 540 cbuf = fz_new_buffer_from_copied_data(ctx, jpx->icc_profile_buf, jpx->icc_profile_len); | |
| 541 state->cs = fz_new_icc_colorspace(ctx, FZ_COLORSPACE_NONE, 0, NULL, cbuf); | |
| 542 } | |
| 543 fz_always(ctx) | |
| 544 fz_drop_buffer(ctx, cbuf); | |
| 545 fz_catch(ctx) | |
| 546 { | |
| 547 fz_rethrow_if(ctx, FZ_ERROR_SYSTEM); | |
| 548 fz_report_error(ctx); | |
| 549 fz_warn(ctx, "ignoring embedded ICC profile in JPX"); | |
| 550 } | |
| 551 | |
| 552 if (state->cs && state->cs->n != n) | |
| 553 { | |
| 554 fz_warn(ctx, "invalid number of components in ICC profile, ignoring ICC profile in JPX"); | |
| 555 fz_drop_colorspace(ctx, state->cs); | |
| 556 state->cs = NULL; | |
| 557 } | |
| 558 } | |
| 559 #endif | |
| 560 | |
| 561 if (!state->cs) | |
| 562 { | |
| 563 switch (n) | |
| 564 { | |
| 565 case 1: state->cs = fz_keep_colorspace(ctx, fz_device_gray(ctx)); break; | |
| 566 case 3: state->cs = fz_keep_colorspace(ctx, fz_device_rgb(ctx)); break; | |
| 567 case 4: state->cs = fz_keep_colorspace(ctx, fz_device_cmyk(ctx)); break; | |
| 568 default: | |
| 569 { | |
| 570 opj_image_destroy(jpx); | |
| 571 fz_throw(ctx, FZ_ERROR_FORMAT, "unsupported number of components: %d", n); | |
| 572 } | |
| 573 } | |
| 574 } | |
| 575 | |
| 576 if (onlymeta) | |
| 577 { | |
| 578 opj_image_destroy(jpx); | |
| 579 return NULL; | |
| 580 } | |
| 581 | |
| 582 fz_try(ctx) | |
| 583 { | |
| 584 a = !!a; /* ignore any superfluous alpha channels */ | |
| 585 img = fz_new_pixmap(ctx, state->cs, w, h, NULL, a); | |
| 586 fz_clear_pixmap_with_value(ctx, img, 0); | |
| 587 copy_jpx_to_pixmap(ctx, img, jpx); | |
| 588 | |
| 589 if (jpx->color_space == OPJ_CLRSPC_SYCC && n == 3 && a == 0) | |
| 590 jpx_ycc_to_rgb(ctx, img, 1, 1); | |
| 591 if (a) | |
| 592 fz_premultiply_pixmap(ctx, img); | |
| 593 } | |
| 594 fz_always(ctx) | |
| 595 { | |
| 596 fz_drop_colorspace(ctx, state->cs); | |
| 597 opj_image_destroy(jpx); | |
| 598 } | |
| 599 fz_catch(ctx) | |
| 600 { | |
| 601 fz_drop_pixmap(ctx, img); | |
| 602 fz_rethrow(ctx); | |
| 603 } | |
| 604 | |
| 605 return img; | |
| 606 } | |
| 607 | |
| 608 fz_pixmap * | |
| 609 fz_load_jpx(fz_context *ctx, const unsigned char *data, size_t size, fz_colorspace *defcs) | |
| 610 { | |
| 611 fz_jpxd state = { 0 }; | |
| 612 fz_pixmap *pix = NULL; | |
| 613 | |
| 614 fz_try(ctx) | |
| 615 { | |
| 616 opj_lock(ctx); | |
| 617 pix = jpx_read_image(ctx, &state, data, size, defcs, 0); | |
| 618 } | |
| 619 fz_always(ctx) | |
| 620 opj_unlock(ctx); | |
| 621 fz_catch(ctx) | |
| 622 fz_rethrow(ctx); | |
| 623 | |
| 624 return pix; | |
| 625 } | |
| 626 | |
| 627 void | |
| 628 fz_load_jpx_info(fz_context *ctx, const unsigned char *data, size_t size, int *wp, int *hp, int *xresp, int *yresp, fz_colorspace **cspacep) | |
| 629 { | |
| 630 fz_jpxd state = { 0 }; | |
| 631 | |
| 632 fz_try(ctx) | |
| 633 { | |
| 634 opj_lock(ctx); | |
| 635 jpx_read_image(ctx, &state, data, size, NULL, 1); | |
| 636 } | |
| 637 fz_always(ctx) | |
| 638 opj_unlock(ctx); | |
| 639 fz_catch(ctx) | |
| 640 fz_rethrow(ctx); | |
| 641 | |
| 642 *cspacep = state.cs; | |
| 643 *wp = state.width; | |
| 644 *hp = state.height; | |
| 645 *xresp = state.xres; | |
| 646 *yresp = state.yres; | |
| 647 } | |
| 648 | |
| 649 #else /* FZ_ENABLE_JPX */ | |
| 650 | |
| 651 fz_pixmap * | |
| 652 fz_load_jpx(fz_context *ctx, const unsigned char *data, size_t size, fz_colorspace *defcs) | |
| 653 { | |
| 654 fz_throw(ctx, FZ_ERROR_UNSUPPORTED, "JPX support disabled"); | |
| 655 } | |
| 656 | |
| 657 void | |
| 658 fz_load_jpx_info(fz_context *ctx, const unsigned char *data, size_t size, int *wp, int *hp, int *xresp, int *yresp, fz_colorspace **cspacep) | |
| 659 { | |
| 660 fz_throw(ctx, FZ_ERROR_UNSUPPORTED, "JPX support disabled"); | |
| 661 } | |
| 662 | |
| 663 #endif |
