Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/leptonica/src/jpegio.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 jpegio.c | |
| 29 * <pre> | |
| 30 * | |
| 31 * Read jpeg from file | |
| 32 * PIX *pixReadJpeg() [special top level] | |
| 33 * PIX *pixReadStreamJpeg() | |
| 34 * | |
| 35 * Read jpeg metadata from file | |
| 36 * l_int32 readHeaderJpeg() | |
| 37 * l_int32 freadHeaderJpeg() | |
| 38 * l_int32 fgetJpegResolution() | |
| 39 * l_int32 fgetJpegComment() | |
| 40 * | |
| 41 * Write jpeg to file | |
| 42 * l_int32 pixWriteJpeg() [special top level] | |
| 43 * l_int32 pixWriteStreamJpeg() | |
| 44 * | |
| 45 * Read/write to memory | |
| 46 * PIX *pixReadMemJpeg() | |
| 47 * l_int32 readHeaderMemJpeg() | |
| 48 * l_int32 readResolutionMemJpeg() | |
| 49 * l_int32 pixWriteMemJpeg() | |
| 50 * | |
| 51 * Setting special flag for chroma sampling on write | |
| 52 * l_int32 pixSetChromaSampling() | |
| 53 * | |
| 54 * Static system helpers | |
| 55 * static void jpeg_error_catch_all_1() | |
| 56 * static void jpeg_error_catch_all_2() | |
| 57 * static l_uint8 jpeg_getc() | |
| 58 * static l_int32 jpeg_comment_callback() | |
| 59 * | |
| 60 * Documentation: libjpeg.doc can be found, along with all | |
| 61 * source code, at ftp://ftp.uu.net/graphics/jpeg | |
| 62 * Download and untar the file: jpegsrc.v6b.tar.gz | |
| 63 * A good paper on jpeg can also be found there: wallace.ps.gz | |
| 64 * | |
| 65 * The functions in libjpeg make it very simple to compress | |
| 66 * and decompress images. On input (decompression from file), | |
| 67 * 3 component color images can be read into either an 8 bpp Pix | |
| 68 * with a colormap or a 32 bpp Pix with RGB components. For output | |
| 69 * (compression to file), all color Pix, whether 8 bpp with a | |
| 70 * colormap or 32 bpp, are written compressed as a set of three | |
| 71 * 8 bpp (rgb) images. | |
| 72 * | |
| 73 * Low-level error handling | |
| 74 * ------------------------ | |
| 75 * The default behavior of the jpeg library is to call exit. | |
| 76 * This is often undesirable, and the caller should make the | |
| 77 * decision when to abort a process. To prevent the jpeg library | |
| 78 * from calling exit(), setjmp() has been inserted into all | |
| 79 * readers and writers, and the cinfo struct has been set up so that | |
| 80 * the low-level jpeg library will call a special error handler | |
| 81 * that doesn't exit, instead of the default function error_exit(). | |
| 82 * | |
| 83 * To avoid race conditions and make these functions thread-safe in | |
| 84 * the rare situation where calls to two threads are simultaneously | |
| 85 * failing on bad jpegs, we insert a local copy of the jmp_buf struct | |
| 86 * into the cinfo.client_data field, and use this on longjmp. | |
| 87 * For extracting the jpeg comment, we have the added complication | |
| 88 * that the client_data field must also return the jpeg comment, | |
| 89 * and we use a different error handler. | |
| 90 * | |
| 91 * How to avoid subsampling the chroma channels | |
| 92 * -------------------------------------------- | |
| 93 * By default, the U,V (chroma) channels use 2x2 subsampling (aka 4.2.0). | |
| 94 * Higher quality for color, using full resolution (4.4.4) for the chroma, | |
| 95 * is obtained by setting a field in the pix before writing: | |
| 96 * pixSetChromaSampling(pix, L_NO_CHROMA_SAMPLING_JPEG); | |
| 97 * The field can be reset for default 4.2.0 subsampling with | |
| 98 * pixSetChromaSampling(pix, 0); | |
| 99 * | |
| 100 * How to extract just the luminance channel in reading RGB | |
| 101 * -------------------------------------------------------- | |
| 102 * For higher resolution and faster decoding of an RGB image, you | |
| 103 * can extract just the 8 bpp luminance channel, using pixReadJpeg(), | |
| 104 * where you use L_JPEG_READ_LUMINANCE for the %hint arg. | |
| 105 * | |
| 106 * How to continue to read if the data is corrupted | |
| 107 * ------------------------------------------------ | |
| 108 * By default, if data is corrupted we make every effort to fail | |
| 109 * to return a pix. (Failure is not always possible with bad | |
| 110 * data, because in some situations, such as during arithmetic | |
| 111 * decoding, the low-level jpeg library will not abort or raise | |
| 112 * a warning.) To attempt to ignore warnings and get a pix when data | |
| 113 * is corrupted, use L_JPEG_CONTINUE_WITH_BAD_DATA in the %hint arg. | |
| 114 * | |
| 115 * Compressing to memory and decompressing from memory | |
| 116 * --------------------------------------------------- | |
| 117 * On systems like Windows without fmemopen() and open_memstream(), | |
| 118 * we write data to a temp file and read it back for operations | |
| 119 * between pix and compressed-data, such as pixReadMemJpeg() and | |
| 120 * pixWriteMemJpeg(). | |
| 121 * </pre> | |
| 122 */ | |
| 123 | |
| 124 #ifdef HAVE_CONFIG_H | |
| 125 #include <config_auto.h> | |
| 126 #endif /* HAVE_CONFIG_H */ | |
| 127 | |
| 128 #include <string.h> | |
| 129 #include "allheaders.h" | |
| 130 #include "pix_internal.h" | |
| 131 | |
| 132 /* --------------------------------------------*/ | |
| 133 #if HAVE_LIBJPEG /* defined in environ.h */ | |
| 134 /* --------------------------------------------*/ | |
| 135 | |
| 136 #include <setjmp.h> | |
| 137 | |
| 138 /* jconfig.h makes the error of setting | |
| 139 * #define HAVE_STDLIB_H | |
| 140 * which conflicts with config_auto.h (where it is set to 1) and results | |
| 141 * for some gcc compiler versions in a warning. The conflict is harmless | |
| 142 * but we suppress it by undefining the variable. */ | |
| 143 #undef HAVE_STDLIB_H | |
| 144 #include "jpeglib.h" | |
| 145 | |
| 146 static void jpeg_error_catch_all_1(j_common_ptr cinfo); | |
| 147 static void jpeg_error_catch_all_2(j_common_ptr cinfo); | |
| 148 static l_uint8 jpeg_getc(j_decompress_ptr cinfo); | |
| 149 | |
| 150 /* Note: 'boolean' is defined in jmorecfg.h. We use it explicitly | |
| 151 * here because for Windows where __MINGW32__ is defined, | |
| 152 * the prototype for jpeg_comment_callback() is given as | |
| 153 * returning a boolean. */ | |
| 154 static boolean jpeg_comment_callback(j_decompress_ptr cinfo); | |
| 155 | |
| 156 /* This is saved in the client_data field of cinfo, and used both | |
| 157 * to retrieve the comment from its callback and to handle | |
| 158 * exceptions with a longjmp. */ | |
| 159 struct callback_data { | |
| 160 jmp_buf jmpbuf; | |
| 161 l_uint8 *comment; | |
| 162 }; | |
| 163 | |
| 164 #ifndef NO_CONSOLE_IO | |
| 165 #define DEBUG_INFO 0 | |
| 166 #endif /* ~NO_CONSOLE_IO */ | |
| 167 | |
| 168 | |
| 169 /*---------------------------------------------------------------------* | |
| 170 * Read jpeg from file (special function) * | |
| 171 *---------------------------------------------------------------------*/ | |
| 172 /*! | |
| 173 * \brief pixReadJpeg() | |
| 174 * | |
| 175 * \param[in] filename | |
| 176 * \param[in] cmapflag 0 for no colormap in returned pix; | |
| 177 * 1 to return an 8 bpp cmapped pix if spp = 3 or 4 | |
| 178 * \param[in] reduction scaling factor: 1, 2, 4 or 8 | |
| 179 * \param[out] pnwarn [optional] number of warnings about | |
| 180 * corrupted data | |
| 181 * \param[in] hint a bitwise OR of L_JPEG_* values; 0 for default | |
| 182 * \return pix, or NULL on error | |
| 183 * | |
| 184 * <pre> | |
| 185 * Notes: | |
| 186 * (1) This is a special function for reading jpeg files. | |
| 187 * (2) Use this if you want the jpeg library to create | |
| 188 * an 8 bpp colormapped image. | |
| 189 * (3) Images reduced by factors of 2, 4 or 8 can be returned | |
| 190 * significantly faster than full resolution images. | |
| 191 * (4) If the jpeg data is bad, depending on the severity of the | |
| 192 * data corruption one of two things will happen: | |
| 193 * (a) 0 or more warnings are generated, or | |
| 194 * (b) the library will immediately attempt to exit. This is | |
| 195 * caught by our error handler and no pix will be returned. | |
| 196 * If data corruption causes a warning, the default action | |
| 197 * is to abort the read. The reason is that malformed jpeg | |
| 198 * data sequences exist that prevent termination of the read. | |
| 199 * To allow the decoding to continue after corrupted data is | |
| 200 * encountered, include L_JPEG_CONTINUE_WITH_BAD_DATA in %hint. | |
| 201 * (5) The possible hint values are given in the enum in imageio.h: | |
| 202 * * L_JPEG_READ_LUMINANCE | |
| 203 * * L_JPEG_CONTINUE_WITH_BAD_DATA | |
| 204 * Default (0) is to do neither, and to fail on warning of data | |
| 205 * corruption. | |
| 206 * </pre> | |
| 207 */ | |
| 208 PIX * | |
| 209 pixReadJpeg(const char *filename, | |
| 210 l_int32 cmapflag, | |
| 211 l_int32 reduction, | |
| 212 l_int32 *pnwarn, | |
| 213 l_int32 hint) | |
| 214 { | |
| 215 l_int32 ret; | |
| 216 l_uint8 *comment; | |
| 217 FILE *fp; | |
| 218 PIX *pix; | |
| 219 | |
| 220 if (pnwarn) *pnwarn = 0; | |
| 221 if (!filename) | |
| 222 return (PIX *)ERROR_PTR("filename not defined", __func__, NULL); | |
| 223 if (cmapflag != 0 && cmapflag != 1) | |
| 224 cmapflag = 0; /* default */ | |
| 225 if (reduction != 1 && reduction != 2 && reduction != 4 && reduction != 8) | |
| 226 return (PIX *)ERROR_PTR("reduction not in {1,2,4,8}", __func__, NULL); | |
| 227 | |
| 228 if ((fp = fopenReadStream(filename)) == NULL) | |
| 229 return (PIX *)ERROR_PTR_1("image file not found", | |
| 230 filename, __func__, NULL); | |
| 231 pix = pixReadStreamJpeg(fp, cmapflag, reduction, pnwarn, hint); | |
| 232 if (pix) { | |
| 233 ret = fgetJpegComment(fp, &comment); | |
| 234 if (!ret && comment) | |
| 235 pixSetText(pix, (char *)comment); | |
| 236 LEPT_FREE(comment); | |
| 237 } | |
| 238 fclose(fp); | |
| 239 | |
| 240 if (!pix) | |
| 241 return (PIX *)ERROR_PTR_1("image not returned", | |
| 242 filename, __func__, NULL); | |
| 243 return pix; | |
| 244 } | |
| 245 | |
| 246 | |
| 247 /*! | |
| 248 * \brief pixReadStreamJpeg() | |
| 249 * | |
| 250 * \param[in] fp file stream | |
| 251 * \param[in] cmapflag 0 for no colormap in returned pix; | |
| 252 * 1 to return an 8 bpp cmapped pix if spp = 3 or 4 | |
| 253 * \param[in] reduction scaling factor: 1, 2, 4 or 8 | |
| 254 * \param[out] pnwarn [optional] number of warnings | |
| 255 * \param[in] hint a bitwise OR of L_JPEG_* values; 0 for default | |
| 256 * \return pix, or NULL on error | |
| 257 * | |
| 258 * <pre> | |
| 259 * Notes: | |
| 260 * (1) For usage, see pixReadJpeg(). | |
| 261 * (2) The jpeg comment, if it exists, is not stored in the pix. | |
| 262 * </pre> | |
| 263 */ | |
| 264 PIX * | |
| 265 pixReadStreamJpeg(FILE *fp, | |
| 266 l_int32 cmapflag, | |
| 267 l_int32 reduction, | |
| 268 l_int32 *pnwarn, | |
| 269 l_int32 hint) | |
| 270 { | |
| 271 l_int32 cyan, yellow, magenta, black, nwarn; | |
| 272 l_int32 i, j, k, rval, gval, bval; | |
| 273 l_int32 nlinesread, abort_on_warning; | |
| 274 l_int32 w, h, wpl, spp, ncolors, cindex, ycck, cmyk; | |
| 275 l_uint32 *data; | |
| 276 l_uint32 *line, *ppixel; | |
| 277 JSAMPROW rowbuffer; | |
| 278 PIX *pix; | |
| 279 PIXCMAP *cmap; | |
| 280 struct jpeg_decompress_struct cinfo = { 0 }; | |
| 281 struct jpeg_error_mgr jerr = { 0 }; | |
| 282 jmp_buf jmpbuf; /* must be local to the function */ | |
| 283 | |
| 284 if (pnwarn) *pnwarn = 0; | |
| 285 if (!fp) | |
| 286 return (PIX *)ERROR_PTR("fp not defined", __func__, NULL); | |
| 287 if (cmapflag != 0 && cmapflag != 1) | |
| 288 cmapflag = 0; /* default */ | |
| 289 if (reduction != 1 && reduction != 2 && reduction != 4 && reduction != 8) | |
| 290 return (PIX *)ERROR_PTR("reduction not in {1,2,4,8}", __func__, NULL); | |
| 291 | |
| 292 if (BITS_IN_JSAMPLE != 8) /* set in jmorecfg.h */ | |
| 293 return (PIX *)ERROR_PTR("BITS_IN_JSAMPLE != 8", __func__, NULL); | |
| 294 | |
| 295 rewind(fp); | |
| 296 pix = NULL; | |
| 297 rowbuffer = NULL; | |
| 298 | |
| 299 /* Modify the jpeg error handling to catch fatal errors */ | |
| 300 cinfo.err = jpeg_std_error(&jerr); | |
| 301 jerr.error_exit = jpeg_error_catch_all_1; | |
| 302 cinfo.client_data = (void *)&jmpbuf; | |
| 303 if (setjmp(jmpbuf)) { | |
| 304 jpeg_destroy_decompress(&cinfo); | |
| 305 pixDestroy(&pix); | |
| 306 LEPT_FREE(rowbuffer); | |
| 307 return (PIX *)ERROR_PTR("internal jpeg error", __func__, NULL); | |
| 308 } | |
| 309 | |
| 310 /* Initialize jpeg structs for decompression */ | |
| 311 jpeg_create_decompress(&cinfo); | |
| 312 jpeg_stdio_src(&cinfo, fp); | |
| 313 jpeg_read_header(&cinfo, TRUE); | |
| 314 cinfo.scale_denom = reduction; | |
| 315 cinfo.scale_num = 1; | |
| 316 jpeg_calc_output_dimensions(&cinfo); | |
| 317 if (hint & L_JPEG_READ_LUMINANCE) { | |
| 318 cinfo.out_color_space = JCS_GRAYSCALE; | |
| 319 spp = 1; | |
| 320 L_INFO("reading luminance channel only\n", __func__); | |
| 321 } else { | |
| 322 spp = cinfo.out_color_components; | |
| 323 } | |
| 324 | |
| 325 /* Allocate the image and a row buffer */ | |
| 326 w = cinfo.output_width; | |
| 327 h = cinfo.output_height; | |
| 328 ycck = (cinfo.jpeg_color_space == JCS_YCCK && spp == 4 && cmapflag == 0); | |
| 329 cmyk = (cinfo.jpeg_color_space == JCS_CMYK && spp == 4 && cmapflag == 0); | |
| 330 if (spp != 1 && spp != 3 && !ycck && !cmyk) { | |
| 331 jpeg_destroy_decompress(&cinfo); | |
| 332 return (PIX *)ERROR_PTR("spp must be 1 or 3, or YCCK or CMYK", | |
| 333 __func__, NULL); | |
| 334 } | |
| 335 if ((spp == 3 && cmapflag == 0) || ycck || cmyk) { /* rgb or 4 bpp color */ | |
| 336 rowbuffer = (JSAMPROW)LEPT_CALLOC(sizeof(JSAMPLE), (size_t)spp * w); | |
| 337 pix = pixCreate(w, h, 32); | |
| 338 } else { /* 8 bpp gray or colormapped */ | |
| 339 rowbuffer = (JSAMPROW)LEPT_CALLOC(sizeof(JSAMPLE), w); | |
| 340 pix = pixCreate(w, h, 8); | |
| 341 } | |
| 342 if (!rowbuffer || !pix) { | |
| 343 LEPT_FREE(rowbuffer); | |
| 344 rowbuffer = NULL; | |
| 345 pixDestroy(&pix); | |
| 346 jpeg_destroy_decompress(&cinfo); | |
| 347 return (PIX *)ERROR_PTR("rowbuffer or pix not made", __func__, NULL); | |
| 348 } | |
| 349 pixSetInputFormat(pix, IFF_JFIF_JPEG); | |
| 350 | |
| 351 /* Initialize decompression. | |
| 352 * Set up a colormap for color quantization if requested. | |
| 353 * Arithmetic coding is rarely used on the jpeg data, but if it | |
| 354 * is, jpeg_start_decompress() handles the decoding. | |
| 355 * With corrupted encoded data, this can take an arbitrarily | |
| 356 * long time, and fuzzers are finding examples. Unfortunately, | |
| 357 * there is no way to get a callback from an error in this phase. */ | |
| 358 if (spp == 1) { /* Grayscale or colormapped */ | |
| 359 jpeg_start_decompress(&cinfo); | |
| 360 } else { /* Color; spp == 3 or YCCK or CMYK */ | |
| 361 if (cmapflag == 0) { /* 24 bit color in 32 bit pix or YCCK/CMYK */ | |
| 362 cinfo.quantize_colors = FALSE; | |
| 363 jpeg_start_decompress(&cinfo); | |
| 364 } else { /* Color quantize to 8 bits */ | |
| 365 cinfo.quantize_colors = TRUE; | |
| 366 cinfo.desired_number_of_colors = 256; | |
| 367 jpeg_start_decompress(&cinfo); | |
| 368 | |
| 369 /* Construct a pix cmap */ | |
| 370 cmap = pixcmapCreate(8); | |
| 371 ncolors = cinfo.actual_number_of_colors; | |
| 372 for (cindex = 0; cindex < ncolors; cindex++) { | |
| 373 rval = cinfo.colormap[0][cindex]; | |
| 374 gval = cinfo.colormap[1][cindex]; | |
| 375 bval = cinfo.colormap[2][cindex]; | |
| 376 pixcmapAddColor(cmap, rval, gval, bval); | |
| 377 } | |
| 378 pixSetColormap(pix, cmap); | |
| 379 } | |
| 380 } | |
| 381 wpl = pixGetWpl(pix); | |
| 382 data = pixGetData(pix); | |
| 383 | |
| 384 /* Decompress. It appears that jpeg_read_scanlines() always | |
| 385 * returns 1 when you ask for one scanline, but we test anyway. | |
| 386 * During decoding of scanlines, warnings are issued if corrupted | |
| 387 * data is found. The default behavior is to abort reading | |
| 388 * when a warning is encountered. By setting the hint to have | |
| 389 * the same bit set as in L_JPEG_CONTINUE_WITH_BAD_DATA, e.g., | |
| 390 * hint = hint | L_JPEG_CONTINUE_WITH_BAD_DATA | |
| 391 * reading will continue after warnings, in an attempt to return | |
| 392 * the (possibly corrupted) image. */ | |
| 393 abort_on_warning = (hint & L_JPEG_CONTINUE_WITH_BAD_DATA) ? 0 : 1; | |
| 394 for (i = 0; i < h; i++) { | |
| 395 nlinesread = jpeg_read_scanlines(&cinfo, &rowbuffer, (JDIMENSION)1); | |
| 396 nwarn = cinfo.err->num_warnings; | |
| 397 if (nlinesread == 0 || (abort_on_warning && nwarn > 0)) { | |
| 398 L_ERROR("read error at scanline %d; nwarn = %d\n", | |
| 399 __func__, i, nwarn); | |
| 400 pixDestroy(&pix); | |
| 401 jpeg_destroy_decompress(&cinfo); | |
| 402 LEPT_FREE(rowbuffer); | |
| 403 rowbuffer = NULL; | |
| 404 if (pnwarn) *pnwarn = nwarn; | |
| 405 return (PIX *)ERROR_PTR("bad data", __func__, NULL); | |
| 406 } | |
| 407 | |
| 408 /* -- 24 bit color -- */ | |
| 409 if ((spp == 3 && cmapflag == 0) || ycck || cmyk) { | |
| 410 ppixel = data + i * wpl; | |
| 411 if (spp == 3) { | |
| 412 for (j = k = 0; j < w; j++) { | |
| 413 SET_DATA_BYTE(ppixel, COLOR_RED, rowbuffer[k++]); | |
| 414 SET_DATA_BYTE(ppixel, COLOR_GREEN, rowbuffer[k++]); | |
| 415 SET_DATA_BYTE(ppixel, COLOR_BLUE, rowbuffer[k++]); | |
| 416 ppixel++; | |
| 417 } | |
| 418 } else { | |
| 419 /* This is a conversion from CMYK -> RGB that ignores | |
| 420 color profiles, and is invoked when the image header | |
| 421 claims to be in CMYK or YCCK colorspace. If in YCCK, | |
| 422 libjpeg may be doing YCCK -> CMYK under the hood. | |
| 423 To understand why the colors need to be inverted on | |
| 424 read-in for the Adobe marker, see the "Special | |
| 425 color spaces" section of "Using the IJG JPEG | |
| 426 Library" by Thomas G. Lane: | |
| 427 http://www.jpegcameras.com/libjpeg/libjpeg-3.html#ss3.1 | |
| 428 The non-Adobe conversion is equivalent to: | |
| 429 rval = black - black * cyan / 255 | |
| 430 ... | |
| 431 The Adobe conversion is equivalent to: | |
| 432 rval = black - black * (255 - cyan) / 255 | |
| 433 ... | |
| 434 Note that cyan is the complement to red, and we | |
| 435 are subtracting the complement color (weighted | |
| 436 by black) from black. For Adobe conversions, | |
| 437 where they've already inverted the CMY but not | |
| 438 the K, we have to invert again. The results | |
| 439 must be clipped to [0 ... 255]. */ | |
| 440 for (j = k = 0; j < w; j++) { | |
| 441 cyan = rowbuffer[k++]; | |
| 442 magenta = rowbuffer[k++]; | |
| 443 yellow = rowbuffer[k++]; | |
| 444 black = rowbuffer[k++]; | |
| 445 if (cinfo.saw_Adobe_marker) { | |
| 446 rval = (black * cyan) / 255; | |
| 447 gval = (black * magenta) / 255; | |
| 448 bval = (black * yellow) / 255; | |
| 449 } else { | |
| 450 rval = black * (255 - cyan) / 255; | |
| 451 gval = black * (255 - magenta) / 255; | |
| 452 bval = black * (255 - yellow) / 255; | |
| 453 } | |
| 454 rval = L_MIN(L_MAX(rval, 0), 255); | |
| 455 gval = L_MIN(L_MAX(gval, 0), 255); | |
| 456 bval = L_MIN(L_MAX(bval, 0), 255); | |
| 457 composeRGBPixel(rval, gval, bval, ppixel); | |
| 458 ppixel++; | |
| 459 } | |
| 460 } | |
| 461 } else { /* 8 bpp grayscale or colormapped pix */ | |
| 462 line = data + i * wpl; | |
| 463 for (j = 0; j < w; j++) | |
| 464 SET_DATA_BYTE(line, j, rowbuffer[j]); | |
| 465 } | |
| 466 } | |
| 467 | |
| 468 /* If the pixel density is neither 1 nor 2, it may not be defined. | |
| 469 * In that case, don't set the resolution. */ | |
| 470 if (cinfo.density_unit == 1) { /* pixels per inch */ | |
| 471 pixSetXRes(pix, cinfo.X_density); | |
| 472 pixSetYRes(pix, cinfo.Y_density); | |
| 473 } else if (cinfo.density_unit == 2) { /* pixels per centimeter */ | |
| 474 pixSetXRes(pix, (l_int32)((l_float32)cinfo.X_density * 2.54 + 0.5)); | |
| 475 pixSetYRes(pix, (l_int32)((l_float32)cinfo.Y_density * 2.54 + 0.5)); | |
| 476 } | |
| 477 | |
| 478 if (cinfo.output_components != spp) | |
| 479 lept_stderr("output spp = %d, spp = %d\n", | |
| 480 cinfo.output_components, spp); | |
| 481 | |
| 482 jpeg_finish_decompress(&cinfo); | |
| 483 jpeg_destroy_decompress(&cinfo); | |
| 484 LEPT_FREE(rowbuffer); | |
| 485 rowbuffer = NULL; | |
| 486 if (pnwarn) *pnwarn = nwarn; | |
| 487 if (nwarn > 0) | |
| 488 L_WARNING("%d warning(s) of bad data\n", __func__, nwarn); | |
| 489 return pix; | |
| 490 } | |
| 491 | |
| 492 | |
| 493 /*---------------------------------------------------------------------* | |
| 494 * Read jpeg metadata from file * | |
| 495 *---------------------------------------------------------------------*/ | |
| 496 /*! | |
| 497 * \brief readHeaderJpeg() | |
| 498 * | |
| 499 * \param[in] filename | |
| 500 * \param[out] pw [optional] | |
| 501 * \param[out] ph [optional] | |
| 502 * \param[out] pspp [optional] samples/pixel | |
| 503 * \param[out] pycck [optional] 1 if ycck color space; 0 otherwise | |
| 504 * \param[out] pcmyk [optional] 1 if cmyk color space; 0 otherwise | |
| 505 * \return 0 if OK, 1 on error | |
| 506 */ | |
| 507 l_ok | |
| 508 readHeaderJpeg(const char *filename, | |
| 509 l_int32 *pw, | |
| 510 l_int32 *ph, | |
| 511 l_int32 *pspp, | |
| 512 l_int32 *pycck, | |
| 513 l_int32 *pcmyk) | |
| 514 { | |
| 515 l_int32 ret; | |
| 516 FILE *fp; | |
| 517 | |
| 518 if (pw) *pw = 0; | |
| 519 if (ph) *ph = 0; | |
| 520 if (pspp) *pspp = 0; | |
| 521 if (pycck) *pycck = 0; | |
| 522 if (pcmyk) *pcmyk = 0; | |
| 523 if (!filename) | |
| 524 return ERROR_INT("filename not defined", __func__, 1); | |
| 525 if (!pw && !ph && !pspp && !pycck && !pcmyk) | |
| 526 return ERROR_INT("no results requested", __func__, 1); | |
| 527 | |
| 528 if ((fp = fopenReadStream(filename)) == NULL) | |
| 529 return ERROR_INT_1("image file not found", filename, __func__, 1); | |
| 530 ret = freadHeaderJpeg(fp, pw, ph, pspp, pycck, pcmyk); | |
| 531 fclose(fp); | |
| 532 return ret; | |
| 533 } | |
| 534 | |
| 535 | |
| 536 /*! | |
| 537 * \brief freadHeaderJpeg() | |
| 538 * | |
| 539 * \param[in] fp file stream | |
| 540 * \param[out] pw [optional] | |
| 541 * \param[out] ph [optional] | |
| 542 * \param[out] pspp [optional] samples/pixel | |
| 543 * \param[out] pycck [optional] 1 if ycck color space; 0 otherwise | |
| 544 * \param[out] pcmyk [optional] 1 if cmyk color space; 0 otherwise | |
| 545 * \return 0 if OK, 1 on error | |
| 546 */ | |
| 547 l_ok | |
| 548 freadHeaderJpeg(FILE *fp, | |
| 549 l_int32 *pw, | |
| 550 l_int32 *ph, | |
| 551 l_int32 *pspp, | |
| 552 l_int32 *pycck, | |
| 553 l_int32 *pcmyk) | |
| 554 { | |
| 555 l_int32 spp, w, h; | |
| 556 struct jpeg_decompress_struct cinfo = { 0 }; | |
| 557 struct jpeg_error_mgr jerr = { 0 }; | |
| 558 jmp_buf jmpbuf; /* must be local to the function */ | |
| 559 | |
| 560 if (pw) *pw = 0; | |
| 561 if (ph) *ph = 0; | |
| 562 if (pspp) *pspp = 0; | |
| 563 if (pycck) *pycck = 0; | |
| 564 if (pcmyk) *pcmyk = 0; | |
| 565 if (!fp) | |
| 566 return ERROR_INT("stream not defined", __func__, 1); | |
| 567 if (!pw && !ph && !pspp && !pycck && !pcmyk) | |
| 568 return ERROR_INT("no results requested", __func__, 1); | |
| 569 | |
| 570 rewind(fp); | |
| 571 | |
| 572 /* Modify the jpeg error handling to catch fatal errors */ | |
| 573 cinfo.err = jpeg_std_error(&jerr); | |
| 574 cinfo.client_data = (void *)&jmpbuf; | |
| 575 jerr.error_exit = jpeg_error_catch_all_1; | |
| 576 if (setjmp(jmpbuf)) | |
| 577 return ERROR_INT("internal jpeg error", __func__, 1); | |
| 578 | |
| 579 /* Initialize the jpeg structs for reading the header */ | |
| 580 jpeg_create_decompress(&cinfo); | |
| 581 jpeg_stdio_src(&cinfo, fp); | |
| 582 jpeg_read_header(&cinfo, TRUE); | |
| 583 jpeg_calc_output_dimensions(&cinfo); | |
| 584 spp = cinfo.out_color_components; | |
| 585 w = cinfo.output_width; | |
| 586 h = cinfo.output_height; | |
| 587 if (w < 1 || h < 1 || spp < 1 || spp > 4) { | |
| 588 jpeg_destroy_decompress(&cinfo); | |
| 589 rewind(fp); | |
| 590 return ERROR_INT("bad jpeg image parameters", __func__, 1); | |
| 591 } | |
| 592 | |
| 593 if (pspp) *pspp = spp; | |
| 594 if (pw) *pw = cinfo.output_width; | |
| 595 if (ph) *ph = cinfo.output_height; | |
| 596 if (pycck) *pycck = | |
| 597 (cinfo.jpeg_color_space == JCS_YCCK && spp == 4); | |
| 598 if (pcmyk) *pcmyk = | |
| 599 (cinfo.jpeg_color_space == JCS_CMYK && spp == 4); | |
| 600 | |
| 601 jpeg_destroy_decompress(&cinfo); | |
| 602 rewind(fp); | |
| 603 return 0; | |
| 604 } | |
| 605 | |
| 606 | |
| 607 /* | |
| 608 * \brief fgetJpegResolution() | |
| 609 * | |
| 610 * \param[in] fp file stream | |
| 611 * \param[out] pxres, pyres resolutions | |
| 612 * \return 0 if OK; 1 on error | |
| 613 * | |
| 614 * <pre> | |
| 615 * Notes: | |
| 616 * (1) If neither resolution field is set, this is not an error; | |
| 617 * the returned resolution values are 0 (designating 'unknown'). | |
| 618 * (2) Side-effect: this rewinds the stream. | |
| 619 * </pre> | |
| 620 */ | |
| 621 l_int32 | |
| 622 fgetJpegResolution(FILE *fp, | |
| 623 l_int32 *pxres, | |
| 624 l_int32 *pyres) | |
| 625 { | |
| 626 struct jpeg_decompress_struct cinfo = { 0 }; | |
| 627 struct jpeg_error_mgr jerr = { 0 }; | |
| 628 jmp_buf jmpbuf; /* must be local to the function */ | |
| 629 | |
| 630 if (pxres) *pxres = 0; | |
| 631 if (pyres) *pyres = 0; | |
| 632 if (!pxres || !pyres) | |
| 633 return ERROR_INT("&xres and &yres not both defined", __func__, 1); | |
| 634 if (!fp) | |
| 635 return ERROR_INT("stream not opened", __func__, 1); | |
| 636 | |
| 637 rewind(fp); | |
| 638 | |
| 639 /* Modify the jpeg error handling to catch fatal errors */ | |
| 640 cinfo.err = jpeg_std_error(&jerr); | |
| 641 cinfo.client_data = (void *)&jmpbuf; | |
| 642 jerr.error_exit = jpeg_error_catch_all_1; | |
| 643 if (setjmp(jmpbuf)) | |
| 644 return ERROR_INT("internal jpeg error", __func__, 1); | |
| 645 | |
| 646 /* Initialize the jpeg structs for reading the header */ | |
| 647 jpeg_create_decompress(&cinfo); | |
| 648 jpeg_stdio_src(&cinfo, fp); | |
| 649 jpeg_read_header(&cinfo, TRUE); | |
| 650 | |
| 651 /* It is common for the input resolution to be omitted from the | |
| 652 * jpeg file. If density_unit is not 1 or 2, simply return 0. */ | |
| 653 if (cinfo.density_unit == 1) { /* pixels/inch */ | |
| 654 *pxres = cinfo.X_density; | |
| 655 *pyres = cinfo.Y_density; | |
| 656 } else if (cinfo.density_unit == 2) { /* pixels/cm */ | |
| 657 *pxres = (l_int32)((l_float32)cinfo.X_density * 2.54 + 0.5); | |
| 658 *pyres = (l_int32)((l_float32)cinfo.Y_density * 2.54 + 0.5); | |
| 659 } | |
| 660 | |
| 661 jpeg_destroy_decompress(&cinfo); | |
| 662 rewind(fp); | |
| 663 return 0; | |
| 664 } | |
| 665 | |
| 666 | |
| 667 /* | |
| 668 * \brief fgetJpegComment() | |
| 669 * | |
| 670 * \param[in] fp file stream opened for read | |
| 671 * \param[out] pcomment comment | |
| 672 * \return 0 if OK; 1 on error | |
| 673 * | |
| 674 * <pre> | |
| 675 * Notes: | |
| 676 * (1) Side-effect: this rewinds the stream. | |
| 677 * </pre> | |
| 678 */ | |
| 679 l_int32 | |
| 680 fgetJpegComment(FILE *fp, | |
| 681 l_uint8 **pcomment) | |
| 682 { | |
| 683 struct jpeg_decompress_struct cinfo = { 0 }; | |
| 684 struct jpeg_error_mgr jerr = { 0 }; | |
| 685 struct callback_data cb_data = { 0 }; /* contains local jmp_buf */ | |
| 686 | |
| 687 if (!pcomment) | |
| 688 return ERROR_INT("&comment not defined", __func__, 1); | |
| 689 *pcomment = NULL; | |
| 690 if (!fp) | |
| 691 return ERROR_INT("stream not opened", __func__, 1); | |
| 692 | |
| 693 rewind(fp); | |
| 694 | |
| 695 /* Modify the jpeg error handling to catch fatal errors */ | |
| 696 cinfo.err = jpeg_std_error(&jerr); | |
| 697 jerr.error_exit = jpeg_error_catch_all_2; | |
| 698 cb_data.comment = NULL; | |
| 699 cinfo.client_data = (void *)&cb_data; | |
| 700 if (setjmp(cb_data.jmpbuf)) { | |
| 701 LEPT_FREE(cb_data.comment); | |
| 702 return ERROR_INT("internal jpeg error", __func__, 1); | |
| 703 } | |
| 704 | |
| 705 /* Initialize the jpeg structs for reading the header */ | |
| 706 jpeg_create_decompress(&cinfo); | |
| 707 jpeg_set_marker_processor(&cinfo, JPEG_COM, jpeg_comment_callback); | |
| 708 jpeg_stdio_src(&cinfo, fp); | |
| 709 jpeg_read_header(&cinfo, TRUE); | |
| 710 | |
| 711 /* Save the result */ | |
| 712 *pcomment = cb_data.comment; | |
| 713 jpeg_destroy_decompress(&cinfo); | |
| 714 rewind(fp); | |
| 715 return 0; | |
| 716 } | |
| 717 | |
| 718 | |
| 719 /*---------------------------------------------------------------------* | |
| 720 * Writing Jpeg * | |
| 721 *---------------------------------------------------------------------*/ | |
| 722 /*! | |
| 723 * \brief pixWriteJpeg() | |
| 724 * | |
| 725 * \param[in] filename | |
| 726 * \param[in] pix any depth; cmap is OK | |
| 727 * \param[in] quality 1 - 100; 75 is default | |
| 728 * \param[in] progressive 0 for baseline sequential; 1 for progressive | |
| 729 * \return 0 if OK; 1 on error | |
| 730 */ | |
| 731 l_ok | |
| 732 pixWriteJpeg(const char *filename, | |
| 733 PIX *pix, | |
| 734 l_int32 quality, | |
| 735 l_int32 progressive) | |
| 736 { | |
| 737 FILE *fp; | |
| 738 | |
| 739 if (!pix) | |
| 740 return ERROR_INT("pix not defined", __func__, 1); | |
| 741 if (!filename) | |
| 742 return ERROR_INT("filename not defined", __func__, 1); | |
| 743 | |
| 744 if ((fp = fopenWriteStream(filename, "wb+")) == NULL) | |
| 745 return ERROR_INT_1("stream not opened", filename, __func__, 1); | |
| 746 | |
| 747 if (pixWriteStreamJpeg(fp, pix, quality, progressive)) { | |
| 748 fclose(fp); | |
| 749 return ERROR_INT_1("pix not written to stream", filename, __func__, 1); | |
| 750 } | |
| 751 | |
| 752 fclose(fp); | |
| 753 return 0; | |
| 754 } | |
| 755 | |
| 756 | |
| 757 /*! | |
| 758 * \brief pixWriteStreamJpeg() | |
| 759 * | |
| 760 * \param[in] fp file stream | |
| 761 * \param[in] pixs any depth; cmap is OK | |
| 762 * \param[in] quality 1 - 100; 75 is default value; 0 is also default | |
| 763 * \param[in] progressive 0 for baseline sequential; 1 for progressive | |
| 764 * \return 0 if OK, 1 on error | |
| 765 * | |
| 766 * <pre> | |
| 767 * Notes: | |
| 768 * (1) Progressive encoding gives better compression, at the | |
| 769 * expense of slower encoding and decoding. | |
| 770 * (2) Standard chroma subsampling is 2x2 on both the U and V | |
| 771 * channels. For highest quality, use no subsampling; this | |
| 772 * option is set by pixSetChromaSampling(pix, 0). | |
| 773 * (3) The only valid pixel depths in leptonica are 1, 2, 4, 8, 16 | |
| 774 * and 32 bpp. However, it is possible, and in some cases desirable, | |
| 775 * to write out a jpeg file using an rgb pix that has 24 bpp. | |
| 776 * This can be created by appending the raster data for a 24 bpp | |
| 777 * image (with proper scanline padding) directly to a 24 bpp | |
| 778 * pix that was created without a data array. | |
| 779 * (4) There are two compression paths in this function: | |
| 780 * * Grayscale image, no colormap: compress as 8 bpp image. | |
| 781 * * rgb full color image: copy each line into the color | |
| 782 * line buffer, and compress as three 8 bpp images. | |
| 783 * (5) Under the covers, the jpeg library transforms rgb to a | |
| 784 * luminance-chromaticity triple, each component of which is | |
| 785 * also 8 bits, and compresses that. It uses 2 Huffman tables, | |
| 786 * a higher resolution one (with more quantization levels) | |
| 787 * for luminosity and a lower resolution one for the chromas. | |
| 788 * </pre> | |
| 789 */ | |
| 790 l_ok | |
| 791 pixWriteStreamJpeg(FILE *fp, | |
| 792 PIX *pixs, | |
| 793 l_int32 quality, | |
| 794 l_int32 progressive) | |
| 795 { | |
| 796 l_int32 xres, yres; | |
| 797 l_int32 i, j, k; | |
| 798 l_int32 w, h, d, wpl, spp, colorflag, rowsamples; | |
| 799 l_uint32 *ppixel, *line, *data; | |
| 800 JSAMPROW rowbuffer; | |
| 801 PIX *pix; | |
| 802 struct jpeg_compress_struct cinfo = { 0 }; | |
| 803 struct jpeg_error_mgr jerr = { 0 }; | |
| 804 char *text; | |
| 805 jmp_buf jmpbuf; /* must be local to the function */ | |
| 806 | |
| 807 if (!fp) | |
| 808 return ERROR_INT("stream not open", __func__, 1); | |
| 809 if (!pixs) | |
| 810 return ERROR_INT("pixs not defined", __func__, 1); | |
| 811 if (quality <= 0) quality = 75; /* default */ | |
| 812 if (quality > 100) { | |
| 813 L_ERROR("invalid jpeg quality; setting to 75\n", __func__); | |
| 814 quality = 75; | |
| 815 } | |
| 816 | |
| 817 /* If necessary, convert the pix so that it can be jpeg compressed. | |
| 818 * The colormap is removed based on the source, so if the colormap | |
| 819 * has only gray colors, the image will be compressed with spp = 1. */ | |
| 820 pixGetDimensions(pixs, &w, &h, &d); | |
| 821 pix = NULL; | |
| 822 if (pixGetColormap(pixs) != NULL) { | |
| 823 L_INFO("removing colormap; may be better to compress losslessly\n", | |
| 824 __func__); | |
| 825 pix = pixRemoveColormap(pixs, REMOVE_CMAP_BASED_ON_SRC); | |
| 826 } else if (d >= 8 && d != 16) { /* normal case; no rewrite */ | |
| 827 pix = pixClone(pixs); | |
| 828 } else if (d < 8 || d == 16) { | |
| 829 L_INFO("converting from %d to 8 bpp\n", __func__, d); | |
| 830 pix = pixConvertTo8(pixs, 0); /* 8 bpp, no cmap */ | |
| 831 } else { | |
| 832 L_ERROR("unknown pix type with d = %d and no cmap\n", __func__, d); | |
| 833 return 1; | |
| 834 } | |
| 835 if (!pix) | |
| 836 return ERROR_INT("pix not made", __func__, 1); | |
| 837 pixSetPadBits(pix, 0); | |
| 838 | |
| 839 rewind(fp); | |
| 840 rowbuffer = NULL; | |
| 841 | |
| 842 /* Modify the jpeg error handling to catch fatal errors */ | |
| 843 cinfo.err = jpeg_std_error(&jerr); | |
| 844 cinfo.client_data = (void *)&jmpbuf; | |
| 845 jerr.error_exit = jpeg_error_catch_all_1; | |
| 846 if (setjmp(jmpbuf)) { | |
| 847 LEPT_FREE(rowbuffer); | |
| 848 pixDestroy(&pix); | |
| 849 return ERROR_INT("internal jpeg error", __func__, 1); | |
| 850 } | |
| 851 | |
| 852 /* Initialize the jpeg structs for compression */ | |
| 853 jpeg_create_compress(&cinfo); | |
| 854 jpeg_stdio_dest(&cinfo, fp); | |
| 855 cinfo.image_width = w; | |
| 856 cinfo.image_height = h; | |
| 857 | |
| 858 /* Set the color space and number of components */ | |
| 859 d = pixGetDepth(pix); | |
| 860 if (d == 8) { | |
| 861 colorflag = 0; /* 8 bpp grayscale; no cmap */ | |
| 862 cinfo.input_components = 1; | |
| 863 cinfo.in_color_space = JCS_GRAYSCALE; | |
| 864 } else { /* d == 32 || d == 24 */ | |
| 865 colorflag = 1; /* rgb */ | |
| 866 cinfo.input_components = 3; | |
| 867 cinfo.in_color_space = JCS_RGB; | |
| 868 } | |
| 869 | |
| 870 jpeg_set_defaults(&cinfo); | |
| 871 | |
| 872 /* Setting optimize_coding to TRUE seems to improve compression | |
| 873 * by approx 2-4 percent, and increases comp time by approx 20%. */ | |
| 874 cinfo.optimize_coding = FALSE; | |
| 875 | |
| 876 /* Set resolution in pixels/in (density_unit: 1 = in, 2 = cm) */ | |
| 877 xres = pixGetXRes(pix); | |
| 878 yres = pixGetYRes(pix); | |
| 879 if ((xres != 0) && (yres != 0)) { | |
| 880 cinfo.density_unit = 1; /* designates pixels per inch */ | |
| 881 cinfo.X_density = xres; | |
| 882 cinfo.Y_density = yres; | |
| 883 } | |
| 884 | |
| 885 /* Set the quality and progressive parameters */ | |
| 886 jpeg_set_quality(&cinfo, quality, TRUE); | |
| 887 if (progressive) | |
| 888 jpeg_simple_progression(&cinfo); | |
| 889 | |
| 890 /* Set the chroma subsampling parameters. This is done in | |
| 891 * YUV color space. The Y (intensity) channel is never subsampled. | |
| 892 * The standard subsampling is 2x2 on both the U and V channels. | |
| 893 * Notation on this is confusing. For a nice illustrations, see | |
| 894 * http://en.wikipedia.org/wiki/Chroma_subsampling | |
| 895 * The standard subsampling is written as 4:2:0. | |
| 896 * We allow high quality where there is no subsampling on the | |
| 897 * chroma channels: denoted as 4:4:4. */ | |
| 898 if (pixs->special == L_NO_CHROMA_SAMPLING_JPEG) { | |
| 899 cinfo.comp_info[0].h_samp_factor = 1; | |
| 900 cinfo.comp_info[0].v_samp_factor = 1; | |
| 901 cinfo.comp_info[1].h_samp_factor = 1; | |
| 902 cinfo.comp_info[1].v_samp_factor = 1; | |
| 903 cinfo.comp_info[2].h_samp_factor = 1; | |
| 904 cinfo.comp_info[2].v_samp_factor = 1; | |
| 905 } | |
| 906 | |
| 907 jpeg_start_compress(&cinfo, TRUE); | |
| 908 | |
| 909 /* Cap the text the length limit, 65533, for JPEG_COM payload. | |
| 910 * Just to be safe, subtract 100 to cover the Adobe name space. */ | |
| 911 if ((text = pixGetText(pix)) != NULL) { | |
| 912 if (strlen(text) > 65433) { | |
| 913 L_WARNING("text is %zu bytes; clipping to 65433\n", | |
| 914 __func__, strlen(text)); | |
| 915 text[65433] = '\0'; | |
| 916 } | |
| 917 jpeg_write_marker(&cinfo, JPEG_COM, (const JOCTET *)text, strlen(text)); | |
| 918 } | |
| 919 | |
| 920 /* Allocate row buffer */ | |
| 921 spp = cinfo.input_components; | |
| 922 rowsamples = spp * w; | |
| 923 if ((rowbuffer = (JSAMPROW)LEPT_CALLOC(sizeof(JSAMPLE), rowsamples)) | |
| 924 == NULL) { | |
| 925 pixDestroy(&pix); | |
| 926 return ERROR_INT("calloc fail for rowbuffer", __func__, 1); | |
| 927 } | |
| 928 | |
| 929 data = pixGetData(pix); | |
| 930 wpl = pixGetWpl(pix); | |
| 931 for (i = 0; i < h; i++) { | |
| 932 line = data + i * wpl; | |
| 933 if (colorflag == 0) { /* 8 bpp gray */ | |
| 934 for (j = 0; j < w; j++) | |
| 935 rowbuffer[j] = GET_DATA_BYTE(line, j); | |
| 936 } else { /* colorflag == 1 */ | |
| 937 if (d == 24) { /* See note 3 above; special case of 24 bpp rgb */ | |
| 938 jpeg_write_scanlines(&cinfo, (JSAMPROW *)&line, 1); | |
| 939 } else { /* standard 32 bpp rgb */ | |
| 940 ppixel = line; | |
| 941 for (j = k = 0; j < w; j++) { | |
| 942 rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_RED); | |
| 943 rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_GREEN); | |
| 944 rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_BLUE); | |
| 945 ppixel++; | |
| 946 } | |
| 947 } | |
| 948 } | |
| 949 if (d != 24) | |
| 950 jpeg_write_scanlines(&cinfo, &rowbuffer, 1); | |
| 951 } | |
| 952 jpeg_finish_compress(&cinfo); | |
| 953 | |
| 954 pixDestroy(&pix); | |
| 955 LEPT_FREE(rowbuffer); | |
| 956 rowbuffer = NULL; | |
| 957 jpeg_destroy_compress(&cinfo); | |
| 958 return 0; | |
| 959 } | |
| 960 | |
| 961 | |
| 962 /*---------------------------------------------------------------------* | |
| 963 * Read/write to memory * | |
| 964 *---------------------------------------------------------------------*/ | |
| 965 | |
| 966 /*! | |
| 967 * \brief pixReadMemJpeg() | |
| 968 * | |
| 969 * \param[in] data const; jpeg-encoded | |
| 970 * \param[in] size of data | |
| 971 * \param[in] cmflag colormap flag 0 means return RGB image if color; | |
| 972 * 1 means create a colormap and return | |
| 973 * an 8 bpp colormapped image if color | |
| 974 * \param[in] reduction scaling factor: 1, 2, 4 or 8 | |
| 975 * \param[out] pnwarn [optional] number of warnings | |
| 976 * \param[in] hint a bitwise OR of L_JPEG_* values; 0 for default | |
| 977 * \return pix, or NULL on error | |
| 978 * | |
| 979 * <pre> | |
| 980 * Notes: | |
| 981 * (1) The %size byte of %data must be a null character. | |
| 982 * (2) The only hint flag so far is L_JPEG_READ_LUMINANCE, | |
| 983 * given in the enum in imageio.h. | |
| 984 * (3) See pixReadJpeg() for usage. | |
| 985 * </pre> | |
| 986 */ | |
| 987 PIX * | |
| 988 pixReadMemJpeg(const l_uint8 *data, | |
| 989 size_t size, | |
| 990 l_int32 cmflag, | |
| 991 l_int32 reduction, | |
| 992 l_int32 *pnwarn, | |
| 993 l_int32 hint) | |
| 994 { | |
| 995 l_int32 ret; | |
| 996 l_uint8 *comment; | |
| 997 FILE *fp; | |
| 998 PIX *pix; | |
| 999 | |
| 1000 if (pnwarn) *pnwarn = 0; | |
| 1001 if (!data) | |
| 1002 return (PIX *)ERROR_PTR("data not defined", __func__, NULL); | |
| 1003 | |
| 1004 if ((fp = fopenReadFromMemory(data, size)) == NULL) | |
| 1005 return (PIX *)ERROR_PTR("stream not opened", __func__, NULL); | |
| 1006 pix = pixReadStreamJpeg(fp, cmflag, reduction, pnwarn, hint); | |
| 1007 if (pix) { | |
| 1008 ret = fgetJpegComment(fp, &comment); | |
| 1009 if (!ret && comment) { | |
| 1010 pixSetText(pix, (char *)comment); | |
| 1011 LEPT_FREE(comment); | |
| 1012 } | |
| 1013 } | |
| 1014 fclose(fp); | |
| 1015 if (!pix) L_ERROR("pix not read\n", __func__); | |
| 1016 return pix; | |
| 1017 } | |
| 1018 | |
| 1019 | |
| 1020 /*! | |
| 1021 * \brief readHeaderMemJpeg() | |
| 1022 * | |
| 1023 * \param[in] data const; jpeg-encoded | |
| 1024 * \param[in] size of data | |
| 1025 * \param[out] pw [optional] width | |
| 1026 * \param[out] ph [optional] height | |
| 1027 * \param[out] pspp [optional] samples/pixel | |
| 1028 * \param[out] pycck [optional] 1 if ycck color space; 0 otherwise | |
| 1029 * \param[out] pcmyk [optional] 1 if cmyk color space; 0 otherwise | |
| 1030 * \return 0 if OK, 1 on error | |
| 1031 */ | |
| 1032 l_ok | |
| 1033 readHeaderMemJpeg(const l_uint8 *data, | |
| 1034 size_t size, | |
| 1035 l_int32 *pw, | |
| 1036 l_int32 *ph, | |
| 1037 l_int32 *pspp, | |
| 1038 l_int32 *pycck, | |
| 1039 l_int32 *pcmyk) | |
| 1040 { | |
| 1041 l_int32 ret; | |
| 1042 FILE *fp; | |
| 1043 | |
| 1044 if (pw) *pw = 0; | |
| 1045 if (ph) *ph = 0; | |
| 1046 if (pspp) *pspp = 0; | |
| 1047 if (pycck) *pycck = 0; | |
| 1048 if (pcmyk) *pcmyk = 0; | |
| 1049 if (!data) | |
| 1050 return ERROR_INT("data not defined", __func__, 1); | |
| 1051 if (!pw && !ph && !pspp && !pycck && !pcmyk) | |
| 1052 return ERROR_INT("no results requested", __func__, 1); | |
| 1053 | |
| 1054 if ((fp = fopenReadFromMemory(data, size)) == NULL) | |
| 1055 return ERROR_INT("stream not opened", __func__, 1); | |
| 1056 ret = freadHeaderJpeg(fp, pw, ph, pspp, pycck, pcmyk); | |
| 1057 fclose(fp); | |
| 1058 return ret; | |
| 1059 } | |
| 1060 | |
| 1061 | |
| 1062 /*! | |
| 1063 * \brief readResolutionMemJpeg() | |
| 1064 * | |
| 1065 * \param[in] data const; jpeg-encoded | |
| 1066 * \param[in] size of data | |
| 1067 * \param[out] pxres [optional] | |
| 1068 * \param[out] pyres [optional] | |
| 1069 * \return 0 if OK, 1 on error | |
| 1070 */ | |
| 1071 l_ok | |
| 1072 readResolutionMemJpeg(const l_uint8 *data, | |
| 1073 size_t size, | |
| 1074 l_int32 *pxres, | |
| 1075 l_int32 *pyres) | |
| 1076 { | |
| 1077 l_int32 ret; | |
| 1078 FILE *fp; | |
| 1079 | |
| 1080 if (pxres) *pxres = 0; | |
| 1081 if (pyres) *pyres = 0; | |
| 1082 if (!data) | |
| 1083 return ERROR_INT("data not defined", __func__, 1); | |
| 1084 if (!pxres && !pyres) | |
| 1085 return ERROR_INT("no results requested", __func__, 1); | |
| 1086 | |
| 1087 if ((fp = fopenReadFromMemory(data, size)) == NULL) | |
| 1088 return ERROR_INT("stream not opened", __func__, 1); | |
| 1089 ret = fgetJpegResolution(fp, pxres, pyres); | |
| 1090 fclose(fp); | |
| 1091 return ret; | |
| 1092 } | |
| 1093 | |
| 1094 | |
| 1095 /*! | |
| 1096 * \brief pixWriteMemJpeg() | |
| 1097 * | |
| 1098 * \param[out] pdata data of jpeg compressed image | |
| 1099 * \param[out] psize size of returned data | |
| 1100 * \param[in] pix any depth; cmap is OK | |
| 1101 * \param[in] quality 1 - 100; 75 is default value; 0 is also default | |
| 1102 * \param[in] progressive 0 for baseline sequential; 1 for progressive | |
| 1103 * \return 0 if OK, 1 on error | |
| 1104 * | |
| 1105 * <pre> | |
| 1106 * Notes: | |
| 1107 * (1) See pixWriteStreamJpeg() for usage. This version writes to | |
| 1108 * memory instead of to a file stream. | |
| 1109 * </pre> | |
| 1110 */ | |
| 1111 l_ok | |
| 1112 pixWriteMemJpeg(l_uint8 **pdata, | |
| 1113 size_t *psize, | |
| 1114 PIX *pix, | |
| 1115 l_int32 quality, | |
| 1116 l_int32 progressive) | |
| 1117 { | |
| 1118 l_int32 ret; | |
| 1119 FILE *fp; | |
| 1120 | |
| 1121 if (pdata) *pdata = NULL; | |
| 1122 if (psize) *psize = 0; | |
| 1123 if (!pdata) | |
| 1124 return ERROR_INT("&data not defined", __func__, 1 ); | |
| 1125 if (!psize) | |
| 1126 return ERROR_INT("&size not defined", __func__, 1 ); | |
| 1127 if (!pix) | |
| 1128 return ERROR_INT("&pix not defined", __func__, 1 ); | |
| 1129 | |
| 1130 #if HAVE_FMEMOPEN | |
| 1131 if ((fp = open_memstream((char **)pdata, psize)) == NULL) | |
| 1132 return ERROR_INT("stream not opened", __func__, 1); | |
| 1133 ret = pixWriteStreamJpeg(fp, pix, quality, progressive); | |
| 1134 fputc('\0', fp); | |
| 1135 fclose(fp); | |
| 1136 if (*psize > 0) *psize = *psize - 1; | |
| 1137 #else | |
| 1138 L_INFO("no fmemopen API --> work-around: write to temp file\n", __func__); | |
| 1139 #ifdef _WIN32 | |
| 1140 if ((fp = fopenWriteWinTempfile()) == NULL) | |
| 1141 return ERROR_INT("tmpfile stream not opened", __func__, 1); | |
| 1142 #else | |
| 1143 if ((fp = tmpfile()) == NULL) | |
| 1144 return ERROR_INT("tmpfile stream not opened", __func__, 1); | |
| 1145 #endif /* _WIN32 */ | |
| 1146 ret = pixWriteStreamJpeg(fp, pix, quality, progressive); | |
| 1147 rewind(fp); | |
| 1148 *pdata = l_binaryReadStream(fp, psize); | |
| 1149 fclose(fp); | |
| 1150 #endif /* HAVE_FMEMOPEN */ | |
| 1151 return ret; | |
| 1152 } | |
| 1153 | |
| 1154 | |
| 1155 /*---------------------------------------------------------------------* | |
| 1156 * Setting special flag for chroma sampling on write * | |
| 1157 *---------------------------------------------------------------------*/ | |
| 1158 /*! | |
| 1159 * \brief pixSetChromaSampling() | |
| 1160 * | |
| 1161 * \param[in] pix | |
| 1162 * \param[in] sampling 1 for subsampling; 0 for no subsampling | |
| 1163 * \return 0 if OK, 1 on error | |
| 1164 * | |
| 1165 * <pre> | |
| 1166 * Notes: | |
| 1167 * (1) The default is for 2x2 chroma subsampling because the files are | |
| 1168 * considerably smaller and the appearance is typically satisfactory. | |
| 1169 * To get full resolution output in the chroma channels for | |
| 1170 * jpeg writing, call this with %sampling == 0. | |
| 1171 * </pre> | |
| 1172 */ | |
| 1173 l_ok | |
| 1174 pixSetChromaSampling(PIX *pix, | |
| 1175 l_int32 sampling) | |
| 1176 { | |
| 1177 if (!pix) | |
| 1178 return ERROR_INT("pix not defined", __func__, 1 ); | |
| 1179 if (sampling) | |
| 1180 pixSetSpecial(pix, 0); /* default */ | |
| 1181 else | |
| 1182 pixSetSpecial(pix, L_NO_CHROMA_SAMPLING_JPEG); | |
| 1183 return 0; | |
| 1184 } | |
| 1185 | |
| 1186 | |
| 1187 /*---------------------------------------------------------------------* | |
| 1188 * Static system helpers * | |
| 1189 *---------------------------------------------------------------------*/ | |
| 1190 /*! | |
| 1191 * \brief jpeg_error_catch_all_1() | |
| 1192 * | |
| 1193 * Notes: | |
| 1194 * (1) The default jpeg error_exit() kills the process, but we | |
| 1195 * never want a call to leptonica to kill a process. If you | |
| 1196 * do want this behavior, remove the calls to these error handlers. | |
| 1197 * (2) This is used where cinfo->client_data holds only jmpbuf. | |
| 1198 */ | |
| 1199 static void | |
| 1200 jpeg_error_catch_all_1(j_common_ptr cinfo) | |
| 1201 { | |
| 1202 jmp_buf *pjmpbuf = (jmp_buf *)cinfo->client_data; | |
| 1203 (*cinfo->err->output_message) (cinfo); | |
| 1204 jpeg_destroy(cinfo); | |
| 1205 longjmp(*pjmpbuf, 1); | |
| 1206 } | |
| 1207 | |
| 1208 /*! | |
| 1209 * \brief jpeg_error_catch_all_2() | |
| 1210 * | |
| 1211 * Notes: | |
| 1212 * (1) This is used where cinfo->client_data needs to hold both | |
| 1213 * the jmpbuf and the jpeg comment data. | |
| 1214 * (2) On error, the comment data will be freed by the caller. | |
| 1215 */ | |
| 1216 static void | |
| 1217 jpeg_error_catch_all_2(j_common_ptr cinfo) | |
| 1218 { | |
| 1219 struct callback_data *pcb_data; | |
| 1220 | |
| 1221 pcb_data = (struct callback_data *)cinfo->client_data; | |
| 1222 (*cinfo->err->output_message) (cinfo); | |
| 1223 jpeg_destroy(cinfo); | |
| 1224 longjmp(pcb_data->jmpbuf, 1); | |
| 1225 } | |
| 1226 | |
| 1227 /* This function was borrowed from libjpeg */ | |
| 1228 static l_uint8 | |
| 1229 jpeg_getc(j_decompress_ptr cinfo) | |
| 1230 { | |
| 1231 struct jpeg_source_mgr *datasrc; | |
| 1232 | |
| 1233 datasrc = cinfo->src; | |
| 1234 if (datasrc->bytes_in_buffer == 0) { | |
| 1235 if (! (*datasrc->fill_input_buffer) (cinfo)) { | |
| 1236 return 0; | |
| 1237 } | |
| 1238 } | |
| 1239 datasrc->bytes_in_buffer--; | |
| 1240 return GETJOCTET(*datasrc->next_input_byte++); | |
| 1241 } | |
| 1242 | |
| 1243 /*! | |
| 1244 * \brief jpeg_comment_callback() | |
| 1245 * | |
| 1246 * Notes: | |
| 1247 * (1) This is used to read the jpeg comment (JPEG_COM). | |
| 1248 * See the note above the declaration for why it returns | |
| 1249 * a "boolean". | |
| 1250 */ | |
| 1251 static boolean | |
| 1252 jpeg_comment_callback(j_decompress_ptr cinfo) | |
| 1253 { | |
| 1254 l_int32 length, i; | |
| 1255 l_uint8 *comment; | |
| 1256 struct callback_data *pcb_data; | |
| 1257 | |
| 1258 /* Get the size of the comment */ | |
| 1259 length = jpeg_getc(cinfo) << 8; | |
| 1260 length += jpeg_getc(cinfo); | |
| 1261 length -= 2; | |
| 1262 if (length <= 0) | |
| 1263 return 1; | |
| 1264 | |
| 1265 /* Extract the comment from the file */ | |
| 1266 if ((comment = (l_uint8 *)LEPT_CALLOC(length + 1, sizeof(l_uint8))) == NULL) | |
| 1267 return 0; | |
| 1268 for (i = 0; i < length; i++) | |
| 1269 comment[i] = jpeg_getc(cinfo); | |
| 1270 | |
| 1271 /* Save the comment and return */ | |
| 1272 pcb_data = (struct callback_data *)cinfo->client_data; | |
| 1273 if (pcb_data->comment) { /* clear before overwriting previous comment */ | |
| 1274 LEPT_FREE(pcb_data->comment); | |
| 1275 pcb_data->comment = NULL; | |
| 1276 } | |
| 1277 pcb_data->comment = comment; | |
| 1278 return 1; | |
| 1279 } | |
| 1280 | |
| 1281 /* --------------------------------------------*/ | |
| 1282 #endif /* HAVE_LIBJPEG */ | |
| 1283 /* --------------------------------------------*/ |
