Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/leptonica/src/jp2kio.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 /*====================================================================* | |
| 2 - Copyright (C) 2001 Leptonica. All rights reserved. | |
| 3 - | |
| 4 - Redistribution and use in source and binary forms, with or without | |
| 5 - modification, are permitted provided that the following conditions | |
| 6 - are met: | |
| 7 - 1. Redistributions of source code must retain the above copyright | |
| 8 - notice, this list of conditions and the following disclaimer. | |
| 9 - 2. Redistributions in binary form must reproduce the above | |
| 10 - copyright notice, this list of conditions and the following | |
| 11 - disclaimer in the documentation and/or other materials | |
| 12 - provided with the distribution. | |
| 13 - | |
| 14 - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 15 - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 16 - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| 17 - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY | |
| 18 - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
| 19 - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
| 20 - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
| 21 - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | |
| 22 - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
| 23 - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
| 24 - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 25 *====================================================================*/ | |
| 26 | |
| 27 /*! | |
| 28 * \file jp2kio.c | |
| 29 * <pre> | |
| 30 * | |
| 31 * Read jp2k from file | |
| 32 * PIX *pixReadJp2k() [special top level] | |
| 33 * PIX *pixReadStreamJp2k() | |
| 34 * static PIX *pixReadMemJp2kCore() | |
| 35 * | |
| 36 * Write jp2k to file | |
| 37 * l_int32 pixWriteJp2k() [special top level] | |
| 38 * l_int32 pixWriteStreamJp2k() | |
| 39 * static opj_image_t *pixConvertToOpjImage() | |
| 40 * | |
| 41 * Read/write to memory | |
| 42 * PIX *pixReadMemJp2k() | |
| 43 * l_int32 pixWriteMemJp2k() | |
| 44 * | |
| 45 * Static generator of opj_stream from a memory buffer | |
| 46 * static opj_stream_t *opjCreateMemoryStream() | |
| 47 * [and other static helpers] | |
| 48 * | |
| 49 * Static generator of opj_stream fom a file stream | |
| 50 * static opj_stream_t *opjCreateStream() | |
| 51 * [and other static helpers] | |
| 52 * | |
| 53 * Based on the OpenJPEG distribution: | |
| 54 * http://www.openjpeg.org/ | |
| 55 * The ISO/IEC reference for jpeg2000 is: | |
| 56 * http://www.jpeg.org/public/15444-1annexi.pdf | |
| 57 * | |
| 58 * Compressing to memory and decompressing from memory | |
| 59 * --------------------------------------------------- | |
| 60 * In previous versions, for systems like Windows that do not have | |
| 61 * fmemopen() and open_memstream(), we wrote data to a temp file. | |
| 62 * Now thanks to the contribution of Anton Tykhyy, we use the | |
| 63 * opj_stream interface directly for operations to and from memory. | |
| 64 * The file stream interface for these operations is a wrapper | |
| 65 * around the memory interface. | |
| 66 * | |
| 67 * Pdf can accept jp2k compressed strings directly | |
| 68 * ----------------------------------------------- | |
| 69 * Transcoding (with the uncompress/compress cycle) is not required | |
| 70 * to wrap images that have already been compressed with jp2k in pdf, | |
| 71 * because the pdf format for jp2k includes the full string of the | |
| 72 * jp2k compressed images. This is also true for jpeg compressed | |
| 73 * strings. | |
| 74 * | |
| 75 * N.B. | |
| 76 * * Reading and writing jp2k are supported here for releases 2.1 and later. | |
| 77 * * The openjpeg.h file is installed in an openjpeg-2.X subdirectory. | |
| 78 * * In openjpeg-2.X, reading is slow compared to jpeg or webp, | |
| 79 * and writing is very slow compared to jpeg or webp. | |
| 80 * * Specifying a quality factor for jpeg2000 requires caution. Unlike | |
| 81 * jpeg and webp, which have a sensible scale that goes from 0 (very poor) | |
| 82 * to 100 (nearly lossless), kakadu and openjpeg use idiosyncratic and | |
| 83 * non-intuitive numbers. kakadu uses "rate/distortion" numbers in | |
| 84 * a narrow range around 50,000; openjpeg (and our write interface) | |
| 85 * use SNR. The visually apparent artifacts introduced by compression | |
| 86 * are strongly content-dependent and vary in a highly non-linear | |
| 87 * way with SNR. We take SNR = 34 as default, roughly similar in | |
| 88 * quality to jpeg's default standard of 75. For document images, | |
| 89 * SNR = 25 is very poor, whereas SNR = 45 is nearly lossless. If you | |
| 90 * use the latter, you will pay dearly in the size of the compressed file. | |
| 91 * * The openjpeg interface was massively changed from 1.X to 2.0. | |
| 92 * There were also changes from 2.0 to 2.1. From 2.0 to 2.1, the | |
| 93 * ability to interface to a C file stream was removed permanently. | |
| 94 * Leptonica supports both file stream and memory buffer interfaces | |
| 95 * for every image I/O library, and it requires the libraries to | |
| 96 * support at least one of these. However, because openjpeg-2.1+ provides | |
| 97 * neither, we have brought several static functions over from | |
| 98 * openjpeg-2.0 in order to retain the file stream interface. | |
| 99 * See, for example, our static function opjCreateStream(). | |
| 100 * </pre> | |
| 101 */ | |
| 102 | |
| 103 #ifdef HAVE_CONFIG_H | |
| 104 #include <config_auto.h> | |
| 105 #endif /* HAVE_CONFIG_H */ | |
| 106 | |
| 107 #include <string.h> | |
| 108 #include "allheaders.h" | |
| 109 | |
| 110 /* --------------------------------------------*/ | |
| 111 #if HAVE_LIBJP2K /* defined in environ.h */ | |
| 112 /* --------------------------------------------*/ | |
| 113 | |
| 114 /* Leptonica supports versions 2.1 and later */ | |
| 115 #ifdef LIBJP2K_HEADER | |
| 116 #include LIBJP2K_HEADER | |
| 117 #else | |
| 118 #include <openjpeg.h> | |
| 119 #endif | |
| 120 | |
| 121 /*! For in-memory encoding and decoding of JP2K */ | |
| 122 typedef struct OpjBuffer | |
| 123 { | |
| 124 l_uint8 *data; /*!< data in the buffer */ | |
| 125 size_t size; /*!< size of buffer */ | |
| 126 size_t pos; /*!< position relative to beginning of buffer */ | |
| 127 size_t len; /*!< length of valid data in the buffer */ | |
| 128 } OpjBuffer; | |
| 129 | |
| 130 /* Static converter pix --> opj_image. Used for compressing pix, | |
| 131 * because the codec works on data stored in their raster format. */ | |
| 132 static opj_image_t *pixConvertToOpjImage(PIX *pix); | |
| 133 | |
| 134 /* Static generator of opj_stream from a memory buffer. */ | |
| 135 static opj_stream_t *opjCreateMemoryStream(OpjBuffer *buf, l_int32 is_read); | |
| 136 | |
| 137 /* Static generator of opj_stream from file stream. | |
| 138 * In 2.0.1, this functionality is provided by | |
| 139 * opj_stream_create_default_file_stream(), | |
| 140 * but it was removed in 2.1.0. Because we must have either | |
| 141 * a file stream or a memory interface to the compressed data, | |
| 142 * it is necessary to recreate the stream interface here. */ | |
| 143 static opj_stream_t *opjCreateStream(FILE *fp, l_int32 is_read); | |
| 144 | |
| 145 | |
| 146 /*---------------------------------------------------------------------* | |
| 147 * Callback event handlers * | |
| 148 *---------------------------------------------------------------------*/ | |
| 149 static void error_callback(const char *msg, void *client_data) { | |
| 150 (void)client_data; | |
| 151 fprintf(stdout, "[ERROR] %s", msg); | |
| 152 } | |
| 153 | |
| 154 static void warning_callback(const char *msg, void *client_data) { | |
| 155 (void)client_data; | |
| 156 fprintf(stdout, "[WARNING] %s", msg); | |
| 157 } | |
| 158 | |
| 159 static void info_callback(const char *msg, void *client_data) { | |
| 160 (void)client_data; | |
| 161 fprintf(stdout, "[INFO] %s", msg); | |
| 162 } | |
| 163 | |
| 164 | |
| 165 /*---------------------------------------------------------------------* | |
| 166 * Read jp2k from file (special function) * | |
| 167 *---------------------------------------------------------------------*/ | |
| 168 /*! | |
| 169 * \brief pixReadJp2k() | |
| 170 * | |
| 171 * \param[in] filename | |
| 172 * \param[in] reduction scaling factor: 1, 2, 4, 8, 16 | |
| 173 * \param[in] box [optional] for extracting a subregion, can be null | |
| 174 * \param[in] hint a bitwise OR of L_JP2K_* values; 0 for default | |
| 175 * \param[in] debug output callback messages, etc | |
| 176 * \return pix 8 or 32 bpp, or NULL on error | |
| 177 * | |
| 178 * <pre> | |
| 179 * Notes: | |
| 180 * (1) This is a special function for reading jp2k files. | |
| 181 * The high-level pixReadStream() uses default values: | |
| 182 * %reduction = 1 | |
| 183 * %box = NULL | |
| 184 * (2) This decodes at either full resolution or at a reduction by | |
| 185 * a power of 2. The default value %reduction == 1 gives a full | |
| 186 * resolution image. Use %reduction > 1 to get a reduced image. | |
| 187 * The actual values of %reduction that can be used on an image | |
| 188 * depend on the number of resolution levels chosen when the | |
| 189 * image was compressed. We typically encode using six power-of-2 | |
| 190 * resolution values: 1, 2, 4, 8, 16 and 32. Attempting to read | |
| 191 * with a value representing a reduction level that was not | |
| 192 * stored when the file was written will fail with the message: | |
| 193 * "failed to read the header". | |
| 194 * (3) Use %box to decode only a part of the image. The box is defined | |
| 195 * at full resolution. It is reduced internally by %reduction, | |
| 196 * and clipping to the right and bottom of the image is automatic. | |
| 197 * (4) We presently only handle images with 8 bits/sample (bps). | |
| 198 * If the image has 16 bps, the read will fail. | |
| 199 * (5) There are 4 possible values of samples/pixel (spp). | |
| 200 * The values in brackets give the pixel values in the Pix: | |
| 201 * spp = 1 ==> grayscale [8 bpp grayscale] | |
| 202 * spp = 2 ==> grayscale + alpha [32 bpp rgba] | |
| 203 * spp = 3 ==> rgb [32 bpp rgb] | |
| 204 * spp = 4 ==> rgba [32 bpp rgba] | |
| 205 * (6) The %hint parameter is reserved for future use. | |
| 206 * </pre> | |
| 207 */ | |
| 208 PIX * | |
| 209 pixReadJp2k(const char *filename, | |
| 210 l_uint32 reduction, | |
| 211 BOX *box, | |
| 212 l_int32 hint, | |
| 213 l_int32 debug) | |
| 214 { | |
| 215 FILE *fp; | |
| 216 PIX *pix; | |
| 217 | |
| 218 if (!filename) | |
| 219 return (PIX *)ERROR_PTR("filename not defined", __func__, NULL); | |
| 220 | |
| 221 if ((fp = fopenReadStream(filename)) == NULL) | |
| 222 return (PIX *)ERROR_PTR_1("image file not found", | |
| 223 filename, __func__, NULL); | |
| 224 pix = pixReadStreamJp2k(fp, reduction, box, hint, debug); | |
| 225 fclose(fp); | |
| 226 | |
| 227 if (!pix) | |
| 228 return (PIX *)ERROR_PTR_1("image not returned", | |
| 229 filename, __func__, NULL); | |
| 230 return pix; | |
| 231 } | |
| 232 | |
| 233 | |
| 234 /*! | |
| 235 * \brief pixReadStreamJp2k() | |
| 236 * | |
| 237 * \param[in] fp file stream | |
| 238 * \param[in] reduction scaling factor: 1, 2, 4, 8 | |
| 239 * \param[in] box [optional] for extracting a subregion, can be null | |
| 240 * \param[in] hint a bitwise OR of L_JP2K_* values; 0 for default | |
| 241 * \param[in] debug output callback messages, etc | |
| 242 * \return pix 8 or 32 bpp, or NULL on error | |
| 243 * | |
| 244 * <pre> | |
| 245 * Notes: | |
| 246 * (1) See pixReadJp2k() for usage. | |
| 247 * </pre> | |
| 248 */ | |
| 249 PIX * | |
| 250 pixReadStreamJp2k(FILE *fp, | |
| 251 l_uint32 reduction, | |
| 252 BOX *box, | |
| 253 l_int32 hint, | |
| 254 l_int32 debug) | |
| 255 { | |
| 256 l_uint8 *data; | |
| 257 size_t size; | |
| 258 PIX *pix; | |
| 259 | |
| 260 if (!fp) | |
| 261 return (PIX *)ERROR_PTR("fp not defined", __func__, NULL); | |
| 262 | |
| 263 /* fgetJp2kResolution() would read the whole stream anyway, | |
| 264 * so we might as well start off by doing that */ | |
| 265 rewind(fp); | |
| 266 if ((data = l_binaryReadStream(fp, &size)) == NULL) | |
| 267 return (PIX *)ERROR_PTR("data not read", __func__, NULL); | |
| 268 | |
| 269 pix = pixReadMemJp2k(data, size, reduction, box, hint, debug); | |
| 270 | |
| 271 LEPT_FREE(data); | |
| 272 return pix; | |
| 273 } | |
| 274 | |
| 275 | |
| 276 static PIX * | |
| 277 pixReadMemJp2kCore(const l_uint8 *bytes, | |
| 278 size_t nbytes, | |
| 279 l_uint32 reduction, | |
| 280 BOX *box, | |
| 281 l_int32 hint, | |
| 282 l_int32 debug) | |
| 283 { | |
| 284 const char *opjVersion; | |
| 285 l_int32 i, j, index, bx, by, bw, bh, val, rval, gval, bval, aval; | |
| 286 l_int32 w, h, wpl, bps, spp, xres, yres, reduce, prec, colorspace; | |
| 287 l_int32 codec; /* L_J2K_CODEC or L_JP2_CODEC */ | |
| 288 l_uint32 pixel; | |
| 289 l_uint32 *data, *line; | |
| 290 opj_dparameters_t parameters; /* decompression parameters */ | |
| 291 opj_image_t *image = NULL; | |
| 292 opj_codec_t *l_codec = NULL; /* handle to decompressor */ | |
| 293 opj_stream_t *l_stream = NULL; /* opj stream */ | |
| 294 PIX *pix = NULL; | |
| 295 OpjBuffer buffer; | |
| 296 | |
| 297 opjVersion = opj_version(); | |
| 298 if (!opjVersion || opjVersion[0] == '\0') | |
| 299 return (PIX *)ERROR_PTR("opj version not defined", __func__, NULL); | |
| 300 if (opjVersion[0] - 0x30 < 2 || | |
| 301 (opjVersion[0] == '2' && opjVersion[2] - 0x30 == 0)) { | |
| 302 L_ERROR("version is %s; must be 2.1 or higher\n", __func__, opjVersion); | |
| 303 return NULL; | |
| 304 } | |
| 305 | |
| 306 /* Get the resolution, bits/sample and codec type */ | |
| 307 readResolutionMemJp2k(bytes, nbytes, &xres, &yres); | |
| 308 readHeaderMemJp2k(bytes, nbytes, NULL, NULL, &bps, NULL, &codec); | |
| 309 if (codec != L_J2K_CODEC && codec != L_JP2_CODEC) { | |
| 310 L_ERROR("valid codec not identified\n", __func__); | |
| 311 return NULL; | |
| 312 } | |
| 313 | |
| 314 if (bps != 8) { | |
| 315 L_ERROR("found %d bps; can only handle 8 bps\n", __func__, bps); | |
| 316 return NULL; | |
| 317 } | |
| 318 | |
| 319 /* Set decoding parameters to default values */ | |
| 320 opj_set_default_decoder_parameters(¶meters); | |
| 321 | |
| 322 /* Find and set the reduce parameter, which is log2(reduction). | |
| 323 * Valid reductions are powers of 2, and are determined when the | |
| 324 * compressed string is made. A request for an invalid reduction | |
| 325 * will cause an error in opj_read_header(), and no image will | |
| 326 * be returned. */ | |
| 327 for (reduce = 0; (1L << reduce) < reduction; reduce++) { } | |
| 328 if ((1L << reduce) != reduction) { | |
| 329 L_ERROR("invalid reduction %d; not power of 2\n", __func__, reduction); | |
| 330 return NULL; | |
| 331 } | |
| 332 parameters.cp_reduce = reduce; | |
| 333 | |
| 334 /* Get a decoder handle */ | |
| 335 if (codec == L_JP2_CODEC) | |
| 336 l_codec = opj_create_decompress(OPJ_CODEC_JP2); | |
| 337 else if (codec == L_J2K_CODEC) | |
| 338 l_codec = opj_create_decompress(OPJ_CODEC_J2K); | |
| 339 if (!l_codec) { | |
| 340 L_ERROR("failed to make the codec\n", __func__); | |
| 341 return NULL; | |
| 342 } | |
| 343 | |
| 344 /* Catch and report events using callbacks */ | |
| 345 if (debug) { | |
| 346 opj_set_info_handler(l_codec, info_callback, NULL); | |
| 347 opj_set_warning_handler(l_codec, warning_callback, NULL); | |
| 348 opj_set_error_handler(l_codec, error_callback, NULL); | |
| 349 } | |
| 350 | |
| 351 /* Setup the decoding parameters using user parameters */ | |
| 352 if (!opj_setup_decoder(l_codec, ¶meters)){ | |
| 353 L_ERROR("failed to set up decoder\n", __func__); | |
| 354 opj_destroy_codec(l_codec); | |
| 355 return NULL; | |
| 356 } | |
| 357 | |
| 358 /* Open decompression 'stream'. */ | |
| 359 buffer.data = (l_uint8 *)bytes; | |
| 360 buffer.size = nbytes; | |
| 361 buffer.len = nbytes; | |
| 362 buffer.pos = 0; | |
| 363 if ((l_stream = opjCreateMemoryStream(&buffer, 1)) == NULL) { | |
| 364 L_ERROR("failed to open the stream\n", __func__); | |
| 365 opj_destroy_codec(l_codec); | |
| 366 return NULL; | |
| 367 } | |
| 368 | |
| 369 /* Read the main header of the codestream and, if necessary, | |
| 370 * the JP2 boxes */ | |
| 371 if(!opj_read_header(l_stream, l_codec, &image)){ | |
| 372 L_ERROR("failed to read the header\n", __func__); | |
| 373 opj_stream_destroy(l_stream); | |
| 374 opj_destroy_codec(l_codec); | |
| 375 opj_image_destroy(image); | |
| 376 return NULL; | |
| 377 } | |
| 378 | |
| 379 /* Set up to decode a rectangular region */ | |
| 380 if (box) { | |
| 381 boxGetGeometry(box, &bx, &by, &bw, &bh); | |
| 382 if (!opj_set_decode_area(l_codec, image, bx, by, | |
| 383 bx + bw, by + bh)) { | |
| 384 L_ERROR("failed to set the region for decoding\n", __func__); | |
| 385 opj_stream_destroy(l_stream); | |
| 386 opj_destroy_codec(l_codec); | |
| 387 opj_image_destroy(image); | |
| 388 return NULL; | |
| 389 } | |
| 390 } | |
| 391 | |
| 392 /* Get the decoded image */ | |
| 393 if (!(opj_decode(l_codec, l_stream, image) && | |
| 394 opj_end_decompress(l_codec, l_stream))) { | |
| 395 L_ERROR("failed to decode the image\n", __func__); | |
| 396 opj_destroy_codec(l_codec); | |
| 397 opj_stream_destroy(l_stream); | |
| 398 opj_image_destroy(image); | |
| 399 return NULL; | |
| 400 } | |
| 401 | |
| 402 /* Finished with the byte stream and the codec */ | |
| 403 opj_stream_destroy(l_stream); | |
| 404 opj_destroy_codec(l_codec); | |
| 405 | |
| 406 /* Get the image parameters */ | |
| 407 spp = image->numcomps; | |
| 408 w = image->comps[0].w; | |
| 409 h = image->comps[0].h; | |
| 410 prec = image->comps[0].prec; | |
| 411 if (prec != bps) | |
| 412 L_WARNING("precision %d != bps %d!\n", __func__, prec, bps); | |
| 413 if (debug) { | |
| 414 L_INFO("w = %d, h = %d, bps = %d, spp = %d\n", | |
| 415 __func__, w, h, bps, spp); | |
| 416 colorspace = image->color_space; | |
| 417 if (colorspace == OPJ_CLRSPC_SRGB) | |
| 418 L_INFO("colorspace is sRGB\n", __func__); | |
| 419 else if (colorspace == OPJ_CLRSPC_GRAY) | |
| 420 L_INFO("colorspace is grayscale\n", __func__); | |
| 421 else if (colorspace == OPJ_CLRSPC_SYCC) | |
| 422 L_INFO("colorspace is YUV\n", __func__); | |
| 423 } | |
| 424 | |
| 425 /* Convert the image to a pix */ | |
| 426 if (spp == 1) | |
| 427 pix = pixCreate(w, h, 8); | |
| 428 else | |
| 429 pix = pixCreate(w, h, 32); | |
| 430 pixSetInputFormat(pix, IFF_JP2); | |
| 431 pixSetResolution(pix, xres, yres); | |
| 432 data = pixGetData(pix); | |
| 433 wpl = pixGetWpl(pix); | |
| 434 index = 0; | |
| 435 if (spp == 1) { | |
| 436 for (i = 0; i < h; i++) { | |
| 437 line = data + i * wpl; | |
| 438 for (j = 0; j < w; j++) { | |
| 439 val = image->comps[0].data[index]; | |
| 440 SET_DATA_BYTE(line, j, val); | |
| 441 index++; | |
| 442 } | |
| 443 } | |
| 444 } else if (spp == 2) { /* convert to RGBA */ | |
| 445 for (i = 0; i < h; i++) { | |
| 446 line = data + i * wpl; | |
| 447 for (j = 0; j < w; j++) { | |
| 448 val = image->comps[0].data[index]; | |
| 449 aval = image->comps[1].data[index]; | |
| 450 composeRGBAPixel(val, val, val, aval, &pixel); | |
| 451 line[j] = pixel; | |
| 452 index++; | |
| 453 } | |
| 454 } | |
| 455 } else if (spp >= 3) { | |
| 456 for (i = 0; i < h; i++) { | |
| 457 line = data + i * wpl; | |
| 458 for (j = 0; j < w; j++) { | |
| 459 rval = image->comps[0].data[index]; | |
| 460 gval = image->comps[1].data[index]; | |
| 461 bval = image->comps[2].data[index]; | |
| 462 if (spp == 3) { | |
| 463 composeRGBPixel(rval, gval, bval, &pixel); | |
| 464 } else { /* spp == 4 */ | |
| 465 aval = image->comps[3].data[index]; | |
| 466 composeRGBAPixel(rval, gval, bval, aval, &pixel); | |
| 467 } | |
| 468 line[j] = pixel; | |
| 469 index++; | |
| 470 } | |
| 471 } | |
| 472 } | |
| 473 | |
| 474 /* Free the opj image data structure */ | |
| 475 opj_image_destroy(image); | |
| 476 | |
| 477 return pix; | |
| 478 } | |
| 479 | |
| 480 | |
| 481 /*---------------------------------------------------------------------* | |
| 482 * Write jp2k to file * | |
| 483 *---------------------------------------------------------------------*/ | |
| 484 /*! | |
| 485 * \brief pixWriteJp2k() | |
| 486 * | |
| 487 * \param[in] filename | |
| 488 * \param[in] pix any depth, cmap is OK | |
| 489 * \param[in] quality SNR > 0; 0 for default (34); 100 for lossless | |
| 490 * \param[in] nlevels resolution levels; 6 or 7; use 0 for default (6) | |
| 491 * \param[in] hint a bitwise OR of L_JP2K_* values; 0 for default | |
| 492 * \param[in] debug output callback messages, etc | |
| 493 * \return 0 if OK; 1 on error | |
| 494 * | |
| 495 * <pre> | |
| 496 * Notes: | |
| 497 * (1) The %quality parameter is the SNR. The useful range is narrow: | |
| 498 * SNR < 27 (terrible quality) | |
| 499 * SNR = 34 (default; approximately equivalent to jpeg quality 75) | |
| 500 * SNR = 40 (very high quality) | |
| 501 * SNR = 45 (nearly lossless) | |
| 502 * Use 0 for default; 100 for lossless. | |
| 503 * (2) The %nlevels parameter is the number of resolution levels | |
| 504 * to be written. Except for very small images, we allow 6 or 7. | |
| 505 * For example, with %nlevels == 6, images with reduction factors | |
| 506 * of 1, 2, 4, 8, 16 and 32 are encoded, and retrieval is done at | |
| 507 * the level requested when reading. For default, use either 0 or 6. | |
| 508 * Small images can constrain %nlevels according to | |
| 509 * 2^(%nlevels - 1) <= Min(w, h) | |
| 510 * and if necessary %nlevels will be reduced to accommodate. | |
| 511 * For example, images with a minimum dimension between 32 and 63 | |
| 512 * can support %nlevels = 6, with reductions up to 32x. An image | |
| 513 * with a minimum dimension smaller than 32 will not support | |
| 514 * 6 nlevels (reductions of 1, 2, 4, 8, 16 and 32). | |
| 515 * (3) By default, we use the JP2 codec. | |
| 516 * (4) The %hint parameter is not yet in use. | |
| 517 * (5) For now, we only support 1 "layer" for quality. | |
| 518 * </pre> | |
| 519 */ | |
| 520 l_ok | |
| 521 pixWriteJp2k(const char *filename, | |
| 522 PIX *pix, | |
| 523 l_int32 quality, | |
| 524 l_int32 nlevels, | |
| 525 l_int32 hint, | |
| 526 l_int32 debug) | |
| 527 { | |
| 528 FILE *fp; | |
| 529 | |
| 530 if (!pix) | |
| 531 return ERROR_INT("pix not defined", __func__, 1); | |
| 532 if (!filename) | |
| 533 return ERROR_INT("filename not defined", __func__, 1); | |
| 534 | |
| 535 if ((fp = fopenWriteStream(filename, "wb+")) == NULL) | |
| 536 return ERROR_INT_1("stream not opened", filename, __func__, 1); | |
| 537 | |
| 538 if (pixWriteStreamJp2k(fp, pix, quality, nlevels, L_JP2_CODEC, | |
| 539 hint, debug)) { | |
| 540 fclose(fp); | |
| 541 return ERROR_INT_1("pix not written to stream", filename, __func__, 1); | |
| 542 } | |
| 543 | |
| 544 fclose(fp); | |
| 545 return 0; | |
| 546 } | |
| 547 | |
| 548 | |
| 549 /*! | |
| 550 * \brief pixWriteOpjStreamJp2k() | |
| 551 * | |
| 552 * \param[in] l_stream OPJ stream | |
| 553 * \param[in] pix any depth, cmap is OK | |
| 554 * \param[in] quality SNR > 0; 0 for default (34); 100 for lossless | |
| 555 * \param[in] nlevels resolution levels; 6 or 7; use 0 for default (6) | |
| 556 * \param[in] codec L_JP2_CODEC or L_J2K_CODEC | |
| 557 * \param[in] hint a bitwise OR of L_JP2K_* values; 0 for default | |
| 558 * \param[in] debug output callback messages, etc | |
| 559 * \return 0 if OK, 1 on error | |
| 560 * <pre> | |
| 561 * Notes: | |
| 562 * (1) See pixWriteJp2k() for usage. | |
| 563 * </pre> | |
| 564 */ | |
| 565 static l_ok | |
| 566 pixWriteOpjStreamJp2k(opj_stream_t *l_stream, | |
| 567 PIX *pix, | |
| 568 l_int32 quality, | |
| 569 l_int32 nlevels, | |
| 570 l_int32 codec, | |
| 571 l_int32 hint, | |
| 572 l_int32 debug) | |
| 573 { | |
| 574 l_int32 i, w, h, d, depth, channels, success; | |
| 575 l_float64 snr; | |
| 576 const char *opjVersion; | |
| 577 PIX *pixs; | |
| 578 opj_cparameters_t parameters; /* compression parameters */ | |
| 579 opj_codec_t* l_codec = NULL;; | |
| 580 opj_image_t *image = NULL; | |
| 581 | |
| 582 if (!l_stream) | |
| 583 return ERROR_INT("stream not open", __func__, 1); | |
| 584 if (!pix) | |
| 585 return ERROR_INT("pix not defined", __func__, 1); | |
| 586 | |
| 587 snr = (l_float64)quality; | |
| 588 if (snr <= 0.0) snr = 34.0; /* default */ | |
| 589 if (snr < 27.0) | |
| 590 L_WARNING("SNR = %d < 27; very low\n", __func__, (l_int32)snr); | |
| 591 if (snr == 100.0) snr = 0.0; /* for lossless */ | |
| 592 if (snr > 45.0) { | |
| 593 L_WARNING("SNR > 45; using lossless encoding\n", __func__); | |
| 594 snr = 0.0; | |
| 595 } | |
| 596 | |
| 597 if (nlevels == 0) nlevels = 6; /* default */ | |
| 598 if (nlevels < 6) { | |
| 599 L_WARNING("nlevels = %d < 6; setting to 6\n", __func__, nlevels); | |
| 600 nlevels = 6; | |
| 601 } | |
| 602 if (nlevels > 7) { | |
| 603 L_WARNING("nlevels = %d > 7; setting to 7\n", __func__, nlevels); | |
| 604 nlevels = 7; | |
| 605 } | |
| 606 | |
| 607 if (codec != L_JP2_CODEC && codec != L_J2K_CODEC) | |
| 608 return ERROR_INT("valid codec not identified\n", __func__, 1); | |
| 609 | |
| 610 opjVersion = opj_version(); | |
| 611 if (!opjVersion || opjVersion[0] == '\0') | |
| 612 return ERROR_INT("opj version not defined", __func__, 1); | |
| 613 if (opjVersion[0] - 0x30 < 2 || | |
| 614 (opjVersion[0] == '2' && opjVersion[2] - 0x30 == 0)) { | |
| 615 L_ERROR("version is %s; must be 2.1 or higher\n", __func__, opjVersion); | |
| 616 return 1; | |
| 617 } | |
| 618 | |
| 619 /* Remove colormap if it exists; result is 8 or 32 bpp */ | |
| 620 pixGetDimensions(pix, &w, &h, &d); | |
| 621 if (d == 24) { | |
| 622 pixs = pixConvert24To32(pix); | |
| 623 } else if (d == 32) { | |
| 624 pixs = pixClone(pix); | |
| 625 } else if (pixGetColormap(pix) == NULL) { | |
| 626 pixs = pixConvertTo8(pix, 0); | |
| 627 } else { /* colormap */ | |
| 628 L_INFO("removing colormap; may be better to compress losslessly\n", | |
| 629 __func__); | |
| 630 pixs = pixRemoveColormap(pix, REMOVE_CMAP_BASED_ON_SRC); | |
| 631 } | |
| 632 depth = pixGetDepth(pixs); /* 8 or 32 */ | |
| 633 | |
| 634 /* Reduce nlevels if the image has at least one small dimension */ | |
| 635 for (i = 1; i < 7; i++) { | |
| 636 if ((w < (1 << i)) || (h < (1 << i))) { | |
| 637 if (i < nlevels) { | |
| 638 L_INFO("small image: w = %d, h = %d; setting nlevels to %d\n", | |
| 639 __func__, w, h, i); | |
| 640 nlevels = i; | |
| 641 } | |
| 642 break; | |
| 643 } | |
| 644 } | |
| 645 | |
| 646 /* Convert to opj image format. */ | |
| 647 pixSetPadBits(pixs, 0); | |
| 648 image = pixConvertToOpjImage(pixs); | |
| 649 pixDestroy(&pixs); | |
| 650 | |
| 651 /* Set encoding parameters to default values. | |
| 652 * We use one layer with the input SNR. */ | |
| 653 opj_set_default_encoder_parameters(¶meters); | |
| 654 parameters.cp_fixed_quality = 1; | |
| 655 parameters.cp_disto_alloc = 0; | |
| 656 parameters.tcp_distoratio[0] = snr; | |
| 657 parameters.tcp_numlayers = 1; | |
| 658 parameters.numresolution = nlevels; | |
| 659 channels = (depth == 32) ? 3 : 1; | |
| 660 parameters.tcp_mct = (channels == 3) ? 1 : 0; | |
| 661 | |
| 662 /* Create comment for codestream */ | |
| 663 if (parameters.cp_comment == NULL) { | |
| 664 const char comment1[] = "Created by Leptonica, version "; | |
| 665 const char comment2[] = "; using OpenJPEG, version "; | |
| 666 size_t len1 = strlen(comment1); | |
| 667 size_t len2 = strlen(comment2); | |
| 668 char *version1 = getLeptonicaVersion(); | |
| 669 const char *version2 = opj_version(); | |
| 670 len1 += len2 + strlen(version1) + strlen(version2) + 1; | |
| 671 parameters.cp_comment = (char *)LEPT_MALLOC(len1); | |
| 672 snprintf(parameters.cp_comment, len1, "%s%s%s%s", comment1, version1, | |
| 673 comment2, version2); | |
| 674 LEPT_FREE(version1); | |
| 675 } | |
| 676 | |
| 677 /* Get the encoder handle */ | |
| 678 if (codec == L_JP2_CODEC) | |
| 679 l_codec = opj_create_compress(OPJ_CODEC_JP2); | |
| 680 else /* codec == L_J2K_CODEC */ | |
| 681 l_codec = opj_create_compress(OPJ_CODEC_J2K); | |
| 682 if (!l_codec) { | |
| 683 opj_image_destroy(image); | |
| 684 LEPT_FREE(parameters.cp_comment); | |
| 685 return ERROR_INT("failed to get the encoder handle\n", __func__, 1); | |
| 686 } | |
| 687 | |
| 688 /* Catch and report events using callbacks */ | |
| 689 if (debug) { | |
| 690 opj_set_info_handler(l_codec, info_callback, NULL); | |
| 691 opj_set_warning_handler(l_codec, warning_callback, NULL); | |
| 692 opj_set_error_handler(l_codec, error_callback, NULL); | |
| 693 } | |
| 694 | |
| 695 /* Set up the encoder */ | |
| 696 if (!opj_setup_encoder(l_codec, ¶meters, image)) { | |
| 697 opj_destroy_codec(l_codec); | |
| 698 opj_image_destroy(image); | |
| 699 LEPT_FREE(parameters.cp_comment); | |
| 700 return ERROR_INT("failed to set up the encoder\n", __func__, 1); | |
| 701 } | |
| 702 | |
| 703 /* Set the resolution (TBD) */ | |
| 704 | |
| 705 /* Encode the image into the l_stream data interface */ | |
| 706 if (!opj_start_compress(l_codec, image, l_stream)) { | |
| 707 opj_destroy_codec(l_codec); | |
| 708 opj_image_destroy(image); | |
| 709 LEPT_FREE(parameters.cp_comment); | |
| 710 return ERROR_INT("opj_start_compress failed\n", __func__, 1); | |
| 711 } | |
| 712 if (!opj_encode(l_codec, l_stream)) { | |
| 713 opj_destroy_codec(l_codec); | |
| 714 opj_image_destroy(image); | |
| 715 LEPT_FREE(parameters.cp_comment); | |
| 716 return ERROR_INT("opj_encode failed\n", __func__, 1); | |
| 717 } | |
| 718 success = opj_end_compress(l_codec, l_stream); | |
| 719 | |
| 720 /* Clean up */ | |
| 721 opj_destroy_codec(l_codec); | |
| 722 opj_image_destroy(image); | |
| 723 LEPT_FREE(parameters.cp_comment); | |
| 724 if (success) | |
| 725 return 0; | |
| 726 else | |
| 727 return ERROR_INT("opj_end_compress failed\n", __func__, 1); | |
| 728 } | |
| 729 | |
| 730 | |
| 731 /*! | |
| 732 * \brief pixWriteStreamJp2k() | |
| 733 * | |
| 734 * \param[in] fp file stream | |
| 735 * \param[in] pix any depth, cmap is OK | |
| 736 * \param[in] quality SNR > 0; 0 for default (34); 100 for lossless | |
| 737 * \param[in] nlevels <= 10 | |
| 738 * \param[in] codec L_JP2_CODEC or L_J2K_CODEC | |
| 739 * \param[in] hint a bitwise OR of L_JP2K_* values; 0 for default | |
| 740 * \param[in] debug output callback messages, etc | |
| 741 * \return 0 if OK, 1 on error | |
| 742 * | |
| 743 * <pre> | |
| 744 * Notes: | |
| 745 * (1) This is a wrapper on the memory stream interface. | |
| 746 * (2) See pixWriteJp2k() for usage. | |
| 747 * </pre> | |
| 748 */ | |
| 749 l_ok | |
| 750 pixWriteStreamJp2k(FILE *fp, | |
| 751 PIX *pix, | |
| 752 l_int32 quality, | |
| 753 l_int32 nlevels, | |
| 754 l_int32 codec, | |
| 755 l_int32 hint, | |
| 756 l_int32 debug) | |
| 757 { | |
| 758 l_ok ok; | |
| 759 opj_stream_t *l_stream; | |
| 760 | |
| 761 if (!fp) | |
| 762 return ERROR_INT("stream not open", __func__, 1); | |
| 763 | |
| 764 /* Open a compression stream for writing, borrowed from | |
| 765 * the 2.0 implementation because the file stream interface | |
| 766 * was removed in 2.1. */ | |
| 767 rewind(fp); | |
| 768 if ((l_stream = opjCreateStream(fp, 0)) == NULL) | |
| 769 return ERROR_INT("failed to open l_stream\n", __func__, 1); | |
| 770 | |
| 771 ok = pixWriteOpjStreamJp2k(l_stream, pix, quality, nlevels, | |
| 772 codec, hint, debug); | |
| 773 | |
| 774 /* Clean up */ | |
| 775 opj_stream_destroy(l_stream); | |
| 776 return ok; | |
| 777 } | |
| 778 | |
| 779 | |
| 780 /*! | |
| 781 * \brief pixConvertToOpjImage() | |
| 782 * | |
| 783 * \param[in] pix 8 or 32 bpp | |
| 784 * \return opj_image, or NULL on error | |
| 785 * | |
| 786 * <pre> | |
| 787 * Notes: | |
| 788 * (1) Input pix is 8 bpp grayscale, 32 bpp rgb, or 32 bpp rgba. | |
| 789 * (2) Gray + alpha pix are all represented as rgba. | |
| 790 * </pre> | |
| 791 */ | |
| 792 static opj_image_t * | |
| 793 pixConvertToOpjImage(PIX *pix) | |
| 794 { | |
| 795 l_int32 i, j, k, w, h, d, spp, wpl; | |
| 796 OPJ_COLOR_SPACE colorspace; | |
| 797 l_int32 *ir = NULL; | |
| 798 l_int32 *ig = NULL; | |
| 799 l_int32 *ib = NULL; | |
| 800 l_int32 *ia = NULL; | |
| 801 l_uint32 *line, *data; | |
| 802 opj_image_t *image; | |
| 803 opj_image_cmptparm_t cmptparm[4]; | |
| 804 | |
| 805 if (!pix) | |
| 806 return (opj_image_t *)ERROR_PTR("pix not defined", __func__, NULL); | |
| 807 pixGetDimensions(pix, &w, &h, &d); | |
| 808 if (d != 8 && d != 32) { | |
| 809 L_ERROR("invalid depth: %d\n", __func__, d); | |
| 810 return NULL; | |
| 811 } | |
| 812 | |
| 813 /* Allocate the opj_image. */ | |
| 814 spp = pixGetSpp(pix); | |
| 815 memset(&cmptparm[0], 0, 4 * sizeof(opj_image_cmptparm_t)); | |
| 816 for (i = 0; i < spp; i++) { | |
| 817 cmptparm[i].prec = 8; | |
| 818 cmptparm[i].sgnd = 0; | |
| 819 cmptparm[i].dx = 1; | |
| 820 cmptparm[i].dy = 1; | |
| 821 cmptparm[i].w = w; | |
| 822 cmptparm[i].h = h; | |
| 823 } | |
| 824 colorspace = (spp == 1) ? OPJ_CLRSPC_GRAY : OPJ_CLRSPC_SRGB; | |
| 825 if ((image = opj_image_create(spp, &cmptparm[0], colorspace)) == NULL) | |
| 826 return (opj_image_t *)ERROR_PTR("image not made", __func__, NULL); | |
| 827 image->x0 = 0; | |
| 828 image->y0 = 0; | |
| 829 image->x1 = w; | |
| 830 image->y1 = h; | |
| 831 | |
| 832 /* Set the component pointers */ | |
| 833 ir = image->comps[0].data; | |
| 834 if (spp > 1) { | |
| 835 ig = image->comps[1].data; | |
| 836 ib = image->comps[2].data; | |
| 837 } | |
| 838 if(spp == 4) | |
| 839 ia = image->comps[3].data; | |
| 840 | |
| 841 /* Transfer the data from the pix */ | |
| 842 data = pixGetData(pix); | |
| 843 wpl = pixGetWpl(pix); | |
| 844 for (i = 0, k = 0; i < h; i++) { | |
| 845 line = data + i * wpl; | |
| 846 for (j = 0; j < w; j++, k++) { | |
| 847 if (spp == 1) { | |
| 848 ir[k] = GET_DATA_BYTE(line, j); | |
| 849 } else if (spp > 1) { | |
| 850 ir[k] = GET_DATA_BYTE(line + j, COLOR_RED); | |
| 851 ig[k] = GET_DATA_BYTE(line + j, COLOR_GREEN); | |
| 852 ib[k] = GET_DATA_BYTE(line + j, COLOR_BLUE); | |
| 853 } | |
| 854 if (spp == 4) | |
| 855 ia[k] = GET_DATA_BYTE(line + j, L_ALPHA_CHANNEL); | |
| 856 } | |
| 857 } | |
| 858 | |
| 859 return image; | |
| 860 } | |
| 861 | |
| 862 | |
| 863 /*---------------------------------------------------------------------* | |
| 864 * Read/write to memory * | |
| 865 *---------------------------------------------------------------------*/ | |
| 866 /*! | |
| 867 * \brief pixReadMemJp2k() | |
| 868 * | |
| 869 * \param[in] data const; jpeg-encoded | |
| 870 * \param[in] size of data | |
| 871 * \param[in] reduction scaling factor: 1, 2, 4, 8 | |
| 872 * \param[in] box [optional] for extracting a subregion, can be null | |
| 873 * \param[in] hint a bitwise OR of L_JP2K_* values; 0 for default | |
| 874 * \param[in] debug output callback messages, etc | |
| 875 * \return pix, or NULL on error | |
| 876 * | |
| 877 * <pre> | |
| 878 * Notes: | |
| 879 * (1) See pixReadJp2k() for usage. | |
| 880 * </pre> | |
| 881 */ | |
| 882 PIX * | |
| 883 pixReadMemJp2k(const l_uint8 *data, | |
| 884 size_t size, | |
| 885 l_uint32 reduction, | |
| 886 BOX *box, | |
| 887 l_int32 hint, | |
| 888 l_int32 debug) | |
| 889 { | |
| 890 PIX *pix; | |
| 891 | |
| 892 if (!data) | |
| 893 return (PIX *)ERROR_PTR("data not defined", __func__, NULL); | |
| 894 | |
| 895 pix = pixReadMemJp2kCore(data, size, reduction, box, hint, debug); | |
| 896 if (!pix) L_ERROR("pix not read\n", __func__); | |
| 897 return pix; | |
| 898 } | |
| 899 | |
| 900 | |
| 901 /*! | |
| 902 * \brief pixWriteMemJp2k() | |
| 903 * | |
| 904 * \param[out] pdata data of jpeg compressed image | |
| 905 * \param[out] psize size of returned data | |
| 906 * \param[in] pix 8 or 32 bpp | |
| 907 * \param[in] quality SNR > 0; 0 for default (34); 100 for lossless | |
| 908 * \param[in] nlevels 0 for default | |
| 909 * \param[in] hint a bitwise OR of L_JP2K_* values; 0 for default | |
| 910 * \param[in] debug output callback messages, etc | |
| 911 * \return 0 if OK, 1 on error | |
| 912 * | |
| 913 * <pre> | |
| 914 * Notes: | |
| 915 * (1) See pixWriteJp2k() for usage. This version writes to | |
| 916 * memory instead of to a file stream. | |
| 917 * </pre> | |
| 918 */ | |
| 919 l_ok | |
| 920 pixWriteMemJp2k(l_uint8 **pdata, | |
| 921 size_t *psize, | |
| 922 PIX *pix, | |
| 923 l_int32 quality, | |
| 924 l_int32 nlevels, | |
| 925 l_int32 hint, | |
| 926 l_int32 debug) | |
| 927 { | |
| 928 l_ok ok; | |
| 929 opj_stream_t *l_stream; | |
| 930 OpjBuffer buffer; | |
| 931 | |
| 932 if (pdata) *pdata = NULL; | |
| 933 if (psize) *psize = 0; | |
| 934 if (!pdata) | |
| 935 return ERROR_INT("&data not defined", __func__, 1 ); | |
| 936 if (!psize) | |
| 937 return ERROR_INT("&size not defined", __func__, 1 ); | |
| 938 if (!pix) | |
| 939 return ERROR_INT("&pix not defined", __func__, 1 ); | |
| 940 | |
| 941 buffer.pos = 0; | |
| 942 buffer.len = 0; | |
| 943 buffer.size = OPJ_J2K_STREAM_CHUNK_SIZE; | |
| 944 buffer.data = (l_uint8 *)LEPT_MALLOC(buffer.size); | |
| 945 if (!buffer.data) | |
| 946 return ERROR_INT("failed to allocate buffer", __func__, 1 ); | |
| 947 | |
| 948 if ((l_stream = opjCreateMemoryStream(&buffer, 0)) == NULL) { | |
| 949 return ERROR_INT("failed to open l_stream\n", __func__, 1); | |
| 950 } | |
| 951 | |
| 952 ok = pixWriteOpjStreamJp2k(l_stream, pix, quality, nlevels, L_JP2_CODEC, | |
| 953 hint, debug); | |
| 954 | |
| 955 /* Clean up */ | |
| 956 opj_stream_destroy(l_stream); | |
| 957 | |
| 958 if (!ok) { | |
| 959 *pdata = buffer.data; | |
| 960 *psize = buffer.len; | |
| 961 } else { | |
| 962 LEPT_FREE(buffer.data); | |
| 963 } | |
| 964 | |
| 965 return ok; | |
| 966 } | |
| 967 | |
| 968 | |
| 969 /*---------------------------------------------------------------------* | |
| 970 * Static functions for the memory stream interface * | |
| 971 *---------------------------------------------------------------------*/ | |
| 972 static OPJ_SIZE_T | |
| 973 opj_read_from_buffer(void *p_buffer, OPJ_SIZE_T p_nb_bytes, OpjBuffer *pbuf) { | |
| 974 if (pbuf->pos > pbuf->len) | |
| 975 return (OPJ_SIZE_T) - 1; | |
| 976 | |
| 977 OPJ_SIZE_T l_nb_read = pbuf->len - pbuf->pos; | |
| 978 if (l_nb_read > p_nb_bytes) | |
| 979 l_nb_read = p_nb_bytes; | |
| 980 memcpy(p_buffer, pbuf->data + pbuf->pos, l_nb_read); | |
| 981 pbuf->pos += l_nb_read; | |
| 982 return l_nb_read ? l_nb_read : (OPJ_SIZE_T) - 1; | |
| 983 } | |
| 984 | |
| 985 static OPJ_SIZE_T | |
| 986 opj_write_from_buffer(const void *p_buffer, OPJ_SIZE_T p_nb_bytes, | |
| 987 OpjBuffer *pbuf) { | |
| 988 size_t newpos = pbuf->pos + p_nb_bytes; | |
| 989 if (newpos > pbuf->size) { | |
| 990 size_t oldsize = pbuf->size; | |
| 991 size_t newsize = oldsize * 2; | |
| 992 if (newsize < newpos) | |
| 993 newsize = newpos; | |
| 994 if (newsize <= 0) { | |
| 995 L_ERROR("buffer too large\n", __func__); | |
| 996 return 0; | |
| 997 } | |
| 998 | |
| 999 l_uint8 *newdata = (l_uint8 *)LEPT_REALLOC(pbuf->data, newsize); | |
| 1000 if (!newdata) { | |
| 1001 L_ERROR("out of memory\n", __func__); | |
| 1002 return 0; | |
| 1003 } | |
| 1004 | |
| 1005 /* clear out any garbage left by realloc */ | |
| 1006 memset(newdata + oldsize, 0, newsize - oldsize); | |
| 1007 pbuf->data = newdata; | |
| 1008 pbuf->size = newsize; | |
| 1009 } | |
| 1010 | |
| 1011 memcpy(pbuf->data + pbuf->pos, p_buffer, p_nb_bytes); | |
| 1012 pbuf->pos = newpos; | |
| 1013 if (pbuf->len < newpos) | |
| 1014 pbuf->len = newpos; | |
| 1015 return p_nb_bytes; | |
| 1016 } | |
| 1017 | |
| 1018 static OPJ_OFF_T | |
| 1019 opj_skip_from_buffer(OPJ_OFF_T offset, OpjBuffer *pbuf) { | |
| 1020 pbuf->pos += offset; | |
| 1021 return offset; | |
| 1022 } | |
| 1023 | |
| 1024 static l_int32 | |
| 1025 opj_seek_from_buffer(OPJ_OFF_T offset, OpjBuffer *pbuf) { | |
| 1026 pbuf->pos = offset; | |
| 1027 return 1; | |
| 1028 } | |
| 1029 | |
| 1030 | |
| 1031 /*---------------------------------------------------------------------* | |
| 1032 * Static generator of opj_stream from memory buffer * | |
| 1033 *---------------------------------------------------------------------*/ | |
| 1034 static opj_stream_t * | |
| 1035 opjCreateMemoryStream(OpjBuffer *pbuf, | |
| 1036 l_int32 is_read_stream) | |
| 1037 { | |
| 1038 opj_stream_t *l_stream; | |
| 1039 | |
| 1040 if (!pbuf) | |
| 1041 return (opj_stream_t *)ERROR_PTR("pbuf not defined", __func__, NULL); | |
| 1042 | |
| 1043 l_stream = opj_stream_create(OPJ_J2K_STREAM_CHUNK_SIZE, is_read_stream); | |
| 1044 if (!l_stream) | |
| 1045 return (opj_stream_t *)ERROR_PTR("stream not made", __func__, NULL); | |
| 1046 | |
| 1047 opj_stream_set_user_data(l_stream, pbuf, | |
| 1048 (opj_stream_free_user_data_fn)NULL); | |
| 1049 opj_stream_set_user_data_length(l_stream, pbuf->len); | |
| 1050 opj_stream_set_read_function(l_stream, | |
| 1051 (opj_stream_read_fn)opj_read_from_buffer); | |
| 1052 opj_stream_set_skip_function(l_stream, | |
| 1053 (opj_stream_skip_fn)opj_skip_from_buffer); | |
| 1054 opj_stream_set_seek_function(l_stream, | |
| 1055 (opj_stream_seek_fn)opj_seek_from_buffer); | |
| 1056 | |
| 1057 if (is_read_stream) | |
| 1058 return l_stream; | |
| 1059 | |
| 1060 opj_stream_set_write_function(l_stream, | |
| 1061 (opj_stream_write_fn)opj_write_from_buffer); | |
| 1062 return l_stream; | |
| 1063 } | |
| 1064 | |
| 1065 | |
| 1066 /*---------------------------------------------------------------------* | |
| 1067 * Static functions from opj 2.0 to retain file stream interface * | |
| 1068 *---------------------------------------------------------------------*/ | |
| 1069 static l_uint64 | |
| 1070 opj_get_user_data_length(FILE *fp) { | |
| 1071 OPJ_OFF_T length = 0; | |
| 1072 fseek(fp, 0, SEEK_END); | |
| 1073 length = (OPJ_OFF_T)ftell(fp); | |
| 1074 fseek(fp, 0, SEEK_SET); | |
| 1075 return (l_uint64)length; | |
| 1076 } | |
| 1077 | |
| 1078 static OPJ_SIZE_T | |
| 1079 opj_read_from_file(void *p_buffer, OPJ_SIZE_T p_nb_bytes, FILE *fp) { | |
| 1080 OPJ_SIZE_T l_nb_read = fread(p_buffer, 1, p_nb_bytes, fp); | |
| 1081 return l_nb_read ? l_nb_read : (OPJ_SIZE_T) - 1; | |
| 1082 } | |
| 1083 | |
| 1084 static OPJ_SIZE_T | |
| 1085 opj_write_from_file(void *p_buffer, OPJ_SIZE_T p_nb_bytes, FILE *fp) | |
| 1086 { | |
| 1087 return fwrite(p_buffer, 1, p_nb_bytes, fp); | |
| 1088 } | |
| 1089 | |
| 1090 static OPJ_OFF_T | |
| 1091 opj_skip_from_file(OPJ_OFF_T offset, FILE *fp) { | |
| 1092 if (fseek(fp, offset, SEEK_CUR)) { | |
| 1093 return -1; | |
| 1094 } | |
| 1095 return offset; | |
| 1096 } | |
| 1097 | |
| 1098 static l_int32 | |
| 1099 opj_seek_from_file(OPJ_OFF_T offset, FILE *fp) { | |
| 1100 if (fseek(fp, offset, SEEK_SET)) { | |
| 1101 return 0; | |
| 1102 } | |
| 1103 return 1; | |
| 1104 } | |
| 1105 | |
| 1106 | |
| 1107 /*---------------------------------------------------------------------* | |
| 1108 * Static generator of opj_stream from a file stream * | |
| 1109 *---------------------------------------------------------------------*/ | |
| 1110 static opj_stream_t * | |
| 1111 opjCreateStream(FILE *fp, | |
| 1112 l_int32 is_read_stream) | |
| 1113 { | |
| 1114 opj_stream_t *l_stream; | |
| 1115 | |
| 1116 if (!fp) | |
| 1117 return (opj_stream_t *)ERROR_PTR("fp not defined", __func__, NULL); | |
| 1118 | |
| 1119 l_stream = opj_stream_create(OPJ_J2K_STREAM_CHUNK_SIZE, is_read_stream); | |
| 1120 if (!l_stream) | |
| 1121 return (opj_stream_t *)ERROR_PTR("stream not made", __func__, NULL); | |
| 1122 | |
| 1123 opj_stream_set_user_data(l_stream, fp, | |
| 1124 (opj_stream_free_user_data_fn)NULL); | |
| 1125 opj_stream_set_user_data_length(l_stream, opj_get_user_data_length(fp)); | |
| 1126 opj_stream_set_read_function(l_stream, | |
| 1127 (opj_stream_read_fn)opj_read_from_file); | |
| 1128 opj_stream_set_write_function(l_stream, | |
| 1129 (opj_stream_write_fn)opj_write_from_file); | |
| 1130 opj_stream_set_skip_function(l_stream, | |
| 1131 (opj_stream_skip_fn)opj_skip_from_file); | |
| 1132 opj_stream_set_seek_function(l_stream, | |
| 1133 (opj_stream_seek_fn)opj_seek_from_file); | |
| 1134 | |
| 1135 return l_stream; | |
| 1136 } | |
| 1137 | |
| 1138 /* --------------------------------------------*/ | |
| 1139 #endif /* HAVE_LIBJP2K */ | |
| 1140 /* --------------------------------------------*/ |
