Leptonica 1.68
C Image Processing Library
|
00001 /*====================================================================* 00002 - Copyright (C) 2001 Leptonica. All rights reserved. 00003 - This software is distributed in the hope that it will be 00004 - useful, but with NO WARRANTY OF ANY KIND. 00005 - No author or distributor accepts responsibility to anyone for the 00006 - consequences of using this software, or for whether it serves any 00007 - particular purpose or works at all, unless he or she says so in 00008 - writing. Everyone is granted permission to copy, modify and 00009 - redistribute this source code, for commercial or non-commercial 00010 - purposes, with the following restrictions: (1) the origin of this 00011 - source code must not be misrepresented; (2) modified versions must 00012 - be plainly marked as such; and (3) this notice may not be removed 00013 - or altered from any source or modified source distribution. 00014 *====================================================================*/ 00015 00016 /* 00017 * jpegio.c 00018 * 00019 * Read jpeg from file 00020 * PIX *pixReadJpeg() [ special top level ] 00021 * PIX *pixReadStreamJpeg() 00022 * 00023 * Read jpeg metadata from file 00024 * l_int32 readHeaderJpeg() 00025 * l_int32 freadHeaderJpeg() 00026 * l_int32 fgetJpegResolution() 00027 * 00028 * Write jpeg to file 00029 * l_int32 pixWriteJpeg() [ special top level ] 00030 * l_int32 pixWriteStreamJpeg() 00031 * 00032 * Read/write to memory 00033 * PIX *pixReadMemJpeg() 00034 * l_int32 readHeaderMemJpeg() 00035 * l_int32 pixWriteMemJpeg() 00036 * 00037 * Setting special flag(s) 00038 * void l_jpegSetNoChromaSampling() 00039 * 00040 * Static system helpers 00041 * static void jpeg_error_do_not_exit() 00042 * static l_uint8 jpeg_getc() 00043 * static l_int32 jpeg_comment_callback() 00044 * 00045 * Extraction of jpeg header information by parsing 00046 * l_int32 extractJpegDataFromFile() 00047 * l_int32 extractJpegDataFromArray() 00048 * static l_int32 extractJpegHeaderDataFallback() 00049 * static l_int32 locateJpegImageParameters() 00050 * static l_int32 getNextJpegMarker() 00051 * static l_int32 getTwoByteParameter() 00052 * 00053 * Documentation: libjpeg.doc can be found, along with all 00054 * source code, at ftp://ftp.uu.net/graphics/jpeg 00055 * Download and untar the file: jpegsrc.v6b.tar.gz 00056 * A good paper on jpeg can also be found there: wallace.ps.gz 00057 * 00058 * The functions in libjpeg make it very simple to compress 00059 * and decompress images. On input (decompression from file), 00060 * 3 component color images can be read into either an 8 bpp Pix 00061 * with a colormap or a 32 bpp Pix with RGB components. For output 00062 * (compression to file), all color Pix, whether 8 bpp with a 00063 * colormap or 32 bpp, are written compressed as a set of three 00064 * 8 bpp (rgb) images. 00065 * 00066 * The default behavior of the jpeg library is to call exit. 00067 * This is often undesirable, and the caller should make the 00068 * decision when to abort a process. So I inserted setjmp(s) 00069 * in the reader and writer, wrote a static error handler that 00070 * does not exit, and set up the cinfo structure so that the 00071 * low-level jpeg library will call this error handler instead 00072 * of the default function error_exit(). 00073 * 00074 * There is a special flag for not subsampling the U,V (chroma) 00075 * channels. This gives higher quality for the color, which is 00076 * important for some situations. The standard subsampling is 00077 * 2x2 on both channels. 00078 * var_JPEG_NO_CHROMA_SAMPLING: default is 0 (false) 00079 * This is set with l_jpegSetNoChromaSampling(). 00080 */ 00081 00082 #include <string.h> 00083 #include "allheaders.h" 00084 00085 #ifdef HAVE_CONFIG_H 00086 #include "config_auto.h" 00087 #endif /* HAVE_CONFIG_H */ 00088 00089 /* --------------------------------------------*/ 00090 #if HAVE_LIBJPEG /* defined in environ.h */ 00091 /* --------------------------------------------*/ 00092 00093 #include <setjmp.h> 00094 00095 /* jconfig.h makes the error of setting 00096 * #define HAVE_STDLIB_H 00097 * which conflicts with config_auto.h (where it is set to 1) and results 00098 * for some gcc compiler versions in a warning. The conflict is harmless 00099 * but we suppress it by undefining the variable. */ 00100 #undef HAVE_STDLIB_H 00101 #include "jpeglib.h" 00102 00103 static void jpeg_error_do_not_exit(j_common_ptr cinfo); 00104 static l_uint8 jpeg_getc(j_decompress_ptr cinfo); 00105 static jmp_buf jpeg_jmpbuf; 00106 00107 /* Note: 'boolean' is defined in jmorecfg.h. We use it explicitly 00108 * here because for windows where __MINGW32__ is defined, 00109 * the prototype for jpeg_comment_callback() is given as 00110 * returning a boolean. */ 00111 static boolean jpeg_comment_callback(j_decompress_ptr cinfo); 00112 00113 /* Static helpers for extraction of jpeg data */ 00114 static l_int32 extractJpegHeaderDataFallback(const void *data, size_t nbytes, 00115 l_int32 *pw, l_int32 *ph, 00116 l_int32 *pbps, l_int32 *pspp); 00117 static l_int32 locateJpegImageParameters(l_uint8 *, size_t, l_int32 *); 00118 static l_int32 getNextJpegMarker(l_uint8 *, size_t, l_int32 *); 00119 static l_int32 getTwoByteParameter(l_uint8 *, l_int32); 00120 00121 00122 /* ----------------Set default for write option ----------------- */ 00123 /* Do not subsample the chroma channels; default is 2x2 subsampling */ 00124 static l_int32 var_JPEG_NO_CHROMA_SAMPLING = 0; 00125 00126 #ifndef NO_CONSOLE_IO 00127 #define DEBUG_INFO 0 00128 #endif /* ~NO_CONSOLE_IO */ 00129 00130 00131 /*---------------------------------------------------------------------* 00132 * Read jpeg from file * 00133 *---------------------------------------------------------------------*/ 00134 /*! 00135 * pixReadJpeg() 00136 * 00137 * Input: filename 00138 * colormap flag (0 means return RGB image if color; 00139 * 1 means create colormap and return 8 bpp 00140 * palette image if color) 00141 * reduction (scaling factor: 1, 2, 4 or 8) 00142 * &pnwarn (<optional return> number of warnings about 00143 * corrupted data) 00144 * Return: pix, or null on error 00145 * 00146 * Images reduced by factors of 2, 4 or 8 can be returned 00147 * significantly faster than full resolution images. 00148 * 00149 * The jpeg library will return warnings (or exit) if 00150 * the jpeg data is bad. Use this function if you want the 00151 * jpeg library to create an 8 bpp palette image, or to 00152 * tell if the jpeg data has been corrupted. For corrupt jpeg 00153 * data, there are two possible outcomes: 00154 * (1) a damaged pix will be returned, along with a nonzero 00155 * number of warnings, or 00156 * (2) for sufficiently serious problems, the library will attempt 00157 * to exit (caught by our error handler) and no pix will be returned. 00158 */ 00159 PIX * 00160 pixReadJpeg(const char *filename, 00161 l_int32 cmflag, 00162 l_int32 reduction, 00163 l_int32 *pnwarn) 00164 { 00165 FILE *fp; 00166 PIX *pix; 00167 00168 PROCNAME("pixReadJpeg"); 00169 00170 if (!filename) 00171 return (PIX *)ERROR_PTR("filename not defined", procName, NULL); 00172 if (pnwarn) 00173 *pnwarn = 0; /* init */ 00174 if (cmflag != 0 && cmflag != 1) 00175 cmflag = 0; /* default */ 00176 if (reduction != 1 && reduction != 2 && reduction != 4 && reduction != 8) 00177 return (PIX *)ERROR_PTR("reduction not in {1,2,4,8}", procName, NULL); 00178 00179 if ((fp = fopenReadStream(filename)) == NULL) 00180 return (PIX *)ERROR_PTR("image file not found", procName, NULL); 00181 pix = pixReadStreamJpeg(fp, cmflag, reduction, pnwarn, 0); 00182 fclose(fp); 00183 00184 if (!pix) 00185 return (PIX *)ERROR_PTR("image not returned", procName, NULL); 00186 return pix; 00187 } 00188 00189 00190 /*! 00191 * pixReadStreamJpeg() 00192 * 00193 * Input: stream 00194 * colormap flag (0 means return RGB image if color; 00195 * 1 means create colormap and return 8 bpp 00196 * palette image if color) 00197 * reduction (scaling factor: 1, 2, 4 or 8) 00198 * &pnwarn (<optional return> number of warnings) 00199 * hint: (a bitwise OR of L_HINT_* values); use 0 for no hints 00200 * Return: pix, or null on error 00201 * 00202 * Usage: see pixReadJpeg() 00203 */ 00204 PIX * 00205 pixReadStreamJpeg(FILE *fp, 00206 l_int32 cmflag, 00207 l_int32 reduction, 00208 l_int32 *pnwarn, 00209 l_int32 hint) 00210 { 00211 l_uint8 cyan, yellow, magenta, black, white; 00212 l_int32 rval, gval, bval; 00213 l_int32 i, j, k; 00214 l_int32 w, h, wpl, spp, ncolors, cindex, ycck, cmyk; 00215 l_uint32 *data; 00216 l_uint32 *line, *ppixel; 00217 JSAMPROW rowbuffer; 00218 PIX *pix; 00219 PIXCMAP *cmap; 00220 struct jpeg_decompress_struct cinfo; 00221 struct jpeg_error_mgr jerr; 00222 l_uint8 *comment = NULL; 00223 00224 PROCNAME("pixReadStreamJpeg"); 00225 00226 if (!fp) 00227 return (PIX *)ERROR_PTR("fp not defined", procName, NULL); 00228 if (pnwarn) 00229 *pnwarn = 0; /* init */ 00230 if (cmflag != 0 && cmflag != 1) 00231 cmflag = 0; /* default */ 00232 if (reduction != 1 && reduction != 2 && reduction != 4 && reduction != 8) 00233 return (PIX *)ERROR_PTR("reduction not in {1,2,4,8}", procName, NULL); 00234 00235 if (BITS_IN_JSAMPLE != 8) /* set in jmorecfg.h */ 00236 return (PIX *)ERROR_PTR("BITS_IN_JSAMPLE != 8", procName, NULL); 00237 00238 rewind(fp); 00239 00240 pix = NULL; /* init */ 00241 if (setjmp(jpeg_jmpbuf)) { 00242 pixDestroy(&pix); 00243 FREE(rowbuffer); 00244 return (PIX *)ERROR_PTR("internal jpeg error", procName, NULL); 00245 } 00246 00247 rowbuffer = NULL; 00248 cinfo.err = jpeg_std_error(&jerr); 00249 jerr.error_exit = jpeg_error_do_not_exit; /* catch error; do not exit! */ 00250 00251 jpeg_create_decompress(&cinfo); 00252 00253 cinfo.client_data = &comment; 00254 jpeg_set_marker_processor(&cinfo, JPEG_COM, jpeg_comment_callback); 00255 jpeg_stdio_src(&cinfo, fp); 00256 jpeg_read_header(&cinfo, TRUE); 00257 cinfo.scale_denom = reduction; 00258 cinfo.scale_num = 1; 00259 if (hint & L_HINT_GRAY) 00260 cinfo.out_color_space = JCS_GRAYSCALE; 00261 jpeg_calc_output_dimensions(&cinfo); 00262 00263 /* Allocate the image and a row buffer */ 00264 spp = cinfo.out_color_components; 00265 w = cinfo.output_width; 00266 h = cinfo.output_height; 00267 ycck = (cinfo.jpeg_color_space == JCS_YCCK && spp == 4 && cmflag == 0); 00268 cmyk = (cinfo.jpeg_color_space == JCS_CMYK && spp == 4 && cmflag == 0); 00269 if (spp != 1 && spp != 3 && !ycck && !cmyk) { 00270 if (comment) FREE(comment); 00271 return (PIX *)ERROR_PTR("spp must be 1 or 3, or YCCK or CMYK", 00272 procName, NULL); 00273 } 00274 if ((spp == 3 && cmflag == 0) || ycck || cmyk) { /* rgb or 4 bpp color */ 00275 rowbuffer = (JSAMPROW)CALLOC(sizeof(JSAMPLE), spp * w); 00276 pix = pixCreate(w, h, 32); 00277 } 00278 else { /* 8 bpp gray or colormapped */ 00279 rowbuffer = (JSAMPROW)CALLOC(sizeof(JSAMPLE), w); 00280 pix = pixCreate(w, h, 8); 00281 } 00282 if (!rowbuffer || !pix) { 00283 if (comment) FREE(comment); 00284 if (rowbuffer) FREE(rowbuffer); 00285 pixDestroy(&pix); 00286 return (PIX *)ERROR_PTR("rowbuffer or pix not made", procName, NULL); 00287 } 00288 00289 if (comment) { 00290 pixSetText(pix, (char *)comment); 00291 FREE(comment); 00292 } 00293 00294 if (spp == 1) /* Grayscale or colormapped */ 00295 jpeg_start_decompress(&cinfo); 00296 else { /* Color; spp == 3 or YCCK or CMYK */ 00297 if (cmflag == 0) { /* -- 24 bit color in 32 bit pix or YCCK/CMYK -- */ 00298 cinfo.quantize_colors = FALSE; 00299 jpeg_start_decompress(&cinfo); 00300 } 00301 else { /* Color quantize to 8 bits */ 00302 cinfo.quantize_colors = TRUE; 00303 cinfo.desired_number_of_colors = 256; 00304 jpeg_start_decompress(&cinfo); 00305 00306 /* Construct a pix cmap */ 00307 cmap = pixcmapCreate(8); 00308 ncolors = cinfo.actual_number_of_colors; 00309 for (cindex = 0; cindex < ncolors; cindex++) 00310 { 00311 rval = cinfo.colormap[0][cindex]; 00312 gval = cinfo.colormap[1][cindex]; 00313 bval = cinfo.colormap[2][cindex]; 00314 pixcmapAddColor(cmap, rval, gval, bval); 00315 } 00316 pixSetColormap(pix, cmap); 00317 } 00318 } 00319 wpl = pixGetWpl(pix); 00320 data = pixGetData(pix); 00321 00322 /* Decompress */ 00323 if ((spp == 3 && cmflag == 0) || ycck || cmyk) { /* -- 24 bit color -- */ 00324 for (i = 0; i < h; i++) { 00325 if (jpeg_read_scanlines(&cinfo, &rowbuffer, (JDIMENSION)1) != 1) 00326 return (PIX *)ERROR_PTR("bad read scanline", procName, NULL); 00327 ppixel = data + i * wpl; 00328 if (spp == 3) { 00329 for (j = k = 0; j < w; j++) { 00330 SET_DATA_BYTE(ppixel, COLOR_RED, rowbuffer[k++]); 00331 SET_DATA_BYTE(ppixel, COLOR_GREEN, rowbuffer[k++]); 00332 SET_DATA_BYTE(ppixel, COLOR_BLUE, rowbuffer[k++]); 00333 ppixel++; 00334 } 00335 } else { 00336 /* This is a conversion from CMYK -> RGB that ignores 00337 color profiles, and is invoked when the image header 00338 claims to be in CMYK or YCCK colorspace. If in YCCK, 00339 libjpeg may be doing YCCK -> CMYK under the hood. 00340 To understand why the colors are inverted on read-in, 00341 see the "Special color spaces" section of 00342 "Using the IJG JPEG Library" by Thomas G. Lane. */ 00343 for (j = k = 0; j < w; j++) { 00344 cyan = 255 - rowbuffer[k++]; 00345 magenta = 255 - rowbuffer[k++]; 00346 yellow = 255 - rowbuffer[k++]; 00347 white = rowbuffer[k++]; 00348 black = 255 - white; 00349 rval = 255 - (cyan * white) / 255 - black; 00350 gval = 255 - (magenta * white) / 255 - black; 00351 bval = 255 - (yellow * white) / 255 - black; 00352 rval = L_MIN(L_MAX(rval, 0), 255); 00353 gval = L_MIN(L_MAX(gval, 0), 255); 00354 bval = L_MIN(L_MAX(bval, 0), 255); 00355 composeRGBPixel(rval, gval, bval, ppixel); 00356 ppixel++; 00357 } 00358 } 00359 } 00360 } 00361 else { /* 8 bpp grayscale or colormapped pix */ 00362 for (i = 0; i < h; i++) { 00363 if (jpeg_read_scanlines(&cinfo, &rowbuffer, (JDIMENSION)1) != 1) 00364 return (PIX *)ERROR_PTR("bad read scanline", procName, NULL); 00365 line = data + i * wpl; 00366 for (j = 0; j < w; j++) 00367 SET_DATA_BYTE(line, j, rowbuffer[j]); 00368 } 00369 } 00370 00371 if (pnwarn) 00372 *pnwarn = cinfo.err->num_warnings; 00373 00374 switch (cinfo.density_unit) 00375 { 00376 case 1: /* pixels per inch */ 00377 pixSetXRes(pix, cinfo.X_density); 00378 pixSetYRes(pix, cinfo.Y_density); 00379 break; 00380 case 2: /* pixels per centimeter */ 00381 pixSetXRes(pix, (l_int32)((l_float32)cinfo.X_density * 2.54 + 0.5)); 00382 pixSetYRes(pix, (l_int32)((l_float32)cinfo.Y_density * 2.54 + 0.5)); 00383 break; 00384 default: /* the pixel density may not be defined; ignore */ 00385 break; 00386 } 00387 00388 jpeg_finish_decompress(&cinfo); 00389 jpeg_destroy_decompress(&cinfo); 00390 FREE(rowbuffer); 00391 00392 return pix; 00393 } 00394 00395 00396 /*---------------------------------------------------------------------* 00397 * Read jpeg metadata from file * 00398 *---------------------------------------------------------------------*/ 00399 /*! 00400 * readHeaderJpeg() 00401 * 00402 * Input: filename 00403 * &w (<optional return>) 00404 * &h (<optional return>) 00405 * &spp (<optional return>, samples/pixel) 00406 * &ycck (<optional return>, 1 if ycck color space; 0 otherwise) 00407 * &cmyk (<optional return>, 1 if cmyk color space; 0 otherwise) 00408 * Return: 0 if OK, 1 on error 00409 */ 00410 l_int32 00411 readHeaderJpeg(const char *filename, 00412 l_int32 *pw, 00413 l_int32 *ph, 00414 l_int32 *pspp, 00415 l_int32 *pycck, 00416 l_int32 *pcmyk) 00417 { 00418 l_int32 ret; 00419 FILE *fp; 00420 00421 PROCNAME("readHeaderJpeg"); 00422 00423 if (!filename) 00424 return ERROR_INT("filename not defined", procName, 1); 00425 if (!pw && !ph && !pspp && !pycck && !pcmyk) 00426 return ERROR_INT("no results requested", procName, 1); 00427 if ((fp = fopenReadStream(filename)) == NULL) 00428 return ERROR_INT("image file not found", procName, 1); 00429 ret = freadHeaderJpeg(fp, pw, ph, pspp, pycck, pcmyk); 00430 fclose(fp); 00431 return ret; 00432 } 00433 00434 00435 /*! 00436 * freadHeaderJpeg() 00437 * 00438 * Input: stream 00439 * &w (<optional return>) 00440 * &h (<optional return>) 00441 * &spp (<optional return>, samples/pixel) 00442 * &ycck (<optional return>, 1 if ycck color space; 0 otherwise) 00443 * &cmyk (<optional return>, 1 if cmyk color space; 0 otherwise) 00444 * Return: 0 if OK, 1 on error 00445 */ 00446 l_int32 00447 freadHeaderJpeg(FILE *fp, 00448 l_int32 *pw, 00449 l_int32 *ph, 00450 l_int32 *pspp, 00451 l_int32 *pycck, 00452 l_int32 *pcmyk) 00453 { 00454 l_int32 spp; 00455 struct jpeg_decompress_struct cinfo; 00456 struct jpeg_error_mgr jerr; 00457 00458 PROCNAME("freadHeaderJpeg"); 00459 00460 if (!fp) 00461 return ERROR_INT("stream not defined", procName, 1); 00462 if (!pw && !ph && !pspp && !pycck && !pcmyk) 00463 return ERROR_INT("no results requested", procName, 1); 00464 00465 if (setjmp(jpeg_jmpbuf)) 00466 return ERROR_INT("internal jpeg error", procName, 1); 00467 00468 rewind(fp); 00469 cinfo.err = jpeg_std_error(&jerr); 00470 jerr.error_exit = jpeg_error_do_not_exit; /* catch error; do not exit! */ 00471 jpeg_create_decompress(&cinfo); 00472 jpeg_stdio_src(&cinfo, fp); 00473 jpeg_read_header(&cinfo, TRUE); 00474 jpeg_calc_output_dimensions(&cinfo); 00475 00476 spp = cinfo.out_color_components; 00477 if (pspp) *pspp = spp; 00478 if (pw) *pw = cinfo.output_width; 00479 if (ph) *ph = cinfo.output_height; 00480 if (pycck) *pycck = 00481 (cinfo.jpeg_color_space == JCS_YCCK && spp == 4); 00482 if (pcmyk) *pcmyk = 00483 (cinfo.jpeg_color_space == JCS_CMYK && spp == 4); 00484 00485 jpeg_destroy_decompress(&cinfo); 00486 rewind(fp); 00487 return 0; 00488 } 00489 00490 00491 /* 00492 * fgetJpegResolution() 00493 * 00494 * Input: stream (opened for read) 00495 * &xres, &yres (<return> resolution in ppi) 00496 * Return: 0 if OK; 1 on error 00497 * 00498 * Notes: 00499 * (1) If neither resolution field is set, this is not an error; 00500 * the returned resolution values are 0 (designating 'unknown'). 00501 * (2) Side-effect: this rewinds the stream. 00502 */ 00503 l_int32 00504 fgetJpegResolution(FILE *fp, 00505 l_int32 *pxres, 00506 l_int32 *pyres) 00507 { 00508 struct jpeg_decompress_struct cinfo; 00509 struct jpeg_error_mgr jerr; 00510 00511 PROCNAME("fgetJpegResolution"); 00512 00513 if (!pxres || !pyres) 00514 return ERROR_INT("&xres and &yres not both defined", procName, 1); 00515 *pxres = *pyres = 0; 00516 if (!fp) 00517 return ERROR_INT("stream not opened", procName, 1); 00518 00519 if (setjmp(jpeg_jmpbuf)) 00520 return ERROR_INT("internal jpeg error", procName, 1); 00521 00522 rewind(fp); 00523 cinfo.err = jpeg_std_error(&jerr); 00524 jerr.error_exit = jpeg_error_do_not_exit; 00525 jpeg_create_decompress(&cinfo); 00526 jpeg_stdio_src(&cinfo, fp); 00527 jpeg_read_header(&cinfo, TRUE); 00528 00529 /* It is common for the input resolution to be omitted from the 00530 * jpeg file. If density_unit is not 1 or 2, simply return 0. */ 00531 if (cinfo.density_unit == 1) { /* pixels/inch */ 00532 *pxres = cinfo.X_density; 00533 *pyres = cinfo.Y_density; 00534 } 00535 else if (cinfo.density_unit == 2) { /* pixels/cm */ 00536 *pxres = (l_int32)((l_float32)cinfo.X_density * 2.54 + 0.5); 00537 *pyres = (l_int32)((l_float32)cinfo.Y_density * 2.54 + 0.5); 00538 } 00539 00540 jpeg_destroy_decompress(&cinfo); 00541 rewind(fp); 00542 return 0; 00543 } 00544 00545 00546 /*---------------------------------------------------------------------* 00547 * Writing Jpeg * 00548 *---------------------------------------------------------------------*/ 00549 /*! 00550 * pixWriteJpeg() 00551 * 00552 * Input: filename 00553 * pix 00554 * quality (1 - 100; 75 is default) 00555 * progressive (0 for baseline sequential; 1 for progressive) 00556 * Return: 0 if OK; 1 on error 00557 */ 00558 l_int32 00559 pixWriteJpeg(const char *filename, 00560 PIX *pix, 00561 l_int32 quality, 00562 l_int32 progressive) 00563 { 00564 FILE *fp; 00565 00566 PROCNAME("pixWriteJpeg"); 00567 00568 if (!pix) 00569 return ERROR_INT("pix not defined", procName, 1); 00570 if (!filename) 00571 return ERROR_INT("filename not defined", procName, 1); 00572 00573 if ((fp = fopenWriteStream(filename, "wb+")) == NULL) 00574 return ERROR_INT("stream not opened", procName, 1); 00575 00576 if (pixWriteStreamJpeg(fp, pix, quality, progressive)) { 00577 fclose(fp); 00578 return ERROR_INT("pix not written to stream", procName, 1); 00579 } 00580 00581 fclose(fp); 00582 return 0; 00583 } 00584 00585 00586 /*! 00587 * pixWriteStreamJpeg() 00588 * 00589 * Input: stream 00590 * pix (8 or 32 bpp) 00591 * quality (1 - 100; 75 is default value; 0 is also default) 00592 * progressive (0 for baseline sequential; 1 for progressive) 00593 * Return: 0 if OK, 1 on error 00594 * 00595 * Notes: 00596 * (1) Under the covers, the library transforms rgb to a 00597 * luminence-chromaticity triple, each component of which is 00598 * also 8 bits, and compresses that. It uses 2 Huffman tables, 00599 * a higher resolution one (with more quantization levels) 00600 * for luminosity and a lower resolution one for the chromas. 00601 * (2) Progressive encoding gives better compression, at the 00602 * expense of slower encoding and decoding. 00603 * (3) Standard chroma subsampling is 2x2 on both the U and V 00604 * channels. For highest quality, use no subsampling. This 00605 * option is set by l_jpegSetNoChromaSampling(1). 00606 * (4) There are three possibilities: 00607 * * Grayscale image, no colormap: compress as 8 bpp image. 00608 * * rgb full color image: copy each line into the color 00609 * line buffer, and compress as three 8 bpp images. 00610 * * 8 bpp colormapped image: convert each line to three 00611 * 8 bpp line images in the color line buffer, and 00612 * compress as three 8 bpp images. 00613 * (5) The only valid pixel depths in leptonica are 1, 2, 4, 8, 16 00614 * and 32 bpp. However, it is possible, and in some cases desirable, 00615 * to write out a jpeg file using an rgb pix that has 24 bpp. 00616 * This can be created by appending the raster data for a 24 bpp 00617 * image (with proper scanline padding) directly to a 24 bpp 00618 * pix that was created without a data array. See note in 00619 * pixWriteStreamPng() for an example. 00620 */ 00621 l_int32 00622 pixWriteStreamJpeg(FILE *fp, 00623 PIX *pix, 00624 l_int32 quality, 00625 l_int32 progressive) 00626 { 00627 l_uint8 byteval; 00628 l_int32 xres, yres; 00629 l_int32 i, j, k; 00630 l_int32 w, h, d, wpl, spp, colorflg, rowsamples; 00631 l_int32 *rmap, *gmap, *bmap; 00632 l_uint32 *ppixel, *line, *data; 00633 JSAMPROW rowbuffer; 00634 PIXCMAP *cmap; 00635 struct jpeg_compress_struct cinfo; 00636 struct jpeg_error_mgr jerr; 00637 const char *text; 00638 00639 PROCNAME("pixWriteStreamJpeg"); 00640 00641 if (!fp) 00642 return ERROR_INT("stream not open", procName, 1); 00643 if (!pix) 00644 return ERROR_INT("pix not defined", procName, 1); 00645 rewind(fp); 00646 00647 if (setjmp(jpeg_jmpbuf)) { 00648 FREE(rowbuffer); 00649 if (colorflg == 1) { 00650 FREE(rmap); 00651 FREE(gmap); 00652 FREE(bmap); 00653 } 00654 return ERROR_INT("internal jpeg error", procName, 1); 00655 } 00656 00657 rowbuffer = NULL; 00658 rmap = NULL; 00659 gmap = NULL; 00660 bmap = NULL; 00661 pixGetDimensions(pix, &w, &h, &d); 00662 if (d != 8 && d != 24 && d != 32) 00663 return ERROR_INT("bpp must be 8, 24 or 32", procName, 1); 00664 00665 if (quality <= 0) 00666 quality = 75; /* default */ 00667 00668 if (d == 32 || d == 24) 00669 colorflg = 2; /* rgb; no colormap */ 00670 else if ((cmap = pixGetColormap(pix)) == NULL) 00671 colorflg = 0; /* 8 bpp grayscale; no colormap */ 00672 else { 00673 colorflg = 1; /* 8 bpp; colormap */ 00674 pixcmapToArrays(cmap, &rmap, &gmap, &bmap); 00675 } 00676 00677 cinfo.err = jpeg_std_error(&jerr); 00678 jerr.error_exit = jpeg_error_do_not_exit; /* catch error; do not exit! */ 00679 00680 jpeg_create_compress(&cinfo); 00681 jpeg_stdio_dest(&cinfo, fp); 00682 00683 cinfo.image_width = w; 00684 cinfo.image_height = h; 00685 00686 if (colorflg == 0) { 00687 cinfo.input_components = 1; 00688 cinfo.in_color_space = JCS_GRAYSCALE; 00689 } 00690 else { /* colorflg == 1 or 2 */ 00691 cinfo.input_components = 3; 00692 cinfo.in_color_space = JCS_RGB; 00693 } 00694 00695 jpeg_set_defaults(&cinfo); 00696 00697 /* Setting optimize_coding to TRUE seems to improve compression 00698 * by approx 2-4 percent, and increases comp time by approx 20%. */ 00699 cinfo.optimize_coding = FALSE; 00700 00701 xres = pixGetXRes(pix); 00702 yres = pixGetYRes(pix); 00703 if ((xres != 0) && (yres != 0)) { 00704 cinfo.density_unit = 1; /* designates pixels per inch */ 00705 cinfo.X_density = xres; 00706 cinfo.Y_density = yres; 00707 } 00708 00709 /* Set the quality and progressive parameters */ 00710 jpeg_set_quality(&cinfo, quality, TRUE); 00711 if (progressive) { 00712 jpeg_simple_progression(&cinfo); 00713 } 00714 00715 /* Set the chroma subsampling parameters. This is done in 00716 * YUV color space. The Y (intensity) channel is never subsampled. 00717 * The standard subsampling is 2x2 on both the U and V channels. 00718 * Notation on this is confusing. For a nice illustrations, see 00719 * http://en.wikipedia.org/wiki/Chroma_subsampling 00720 * The standard subsampling is written as 4:2:0. 00721 * We allow high quality where there is no subsampling on the 00722 * chroma channels: denoted as 4:4:4. */ 00723 if (var_JPEG_NO_CHROMA_SAMPLING == 1) { 00724 cinfo.comp_info[0].h_samp_factor = 1; 00725 cinfo.comp_info[0].v_samp_factor = 1; 00726 cinfo.comp_info[1].h_samp_factor = 1; 00727 cinfo.comp_info[1].v_samp_factor = 1; 00728 cinfo.comp_info[2].h_samp_factor = 1; 00729 cinfo.comp_info[2].v_samp_factor = 1; 00730 } 00731 00732 jpeg_start_compress(&cinfo, TRUE); 00733 00734 if ((text = pixGetText(pix))) { 00735 jpeg_write_marker(&cinfo, JPEG_COM, (const JOCTET *)text, strlen(text)); 00736 } 00737 00738 /* Allocate row buffer */ 00739 spp = cinfo.input_components; 00740 rowsamples = spp * w; 00741 if ((rowbuffer = (JSAMPROW)CALLOC(sizeof(JSAMPLE), rowsamples)) == NULL) 00742 return ERROR_INT("calloc fail for rowbuffer", procName, 1); 00743 00744 data = pixGetData(pix); 00745 wpl = pixGetWpl(pix); 00746 for (i = 0; i < h; i++) { 00747 line = data + i * wpl; 00748 if (colorflg == 0) { /* 8 bpp gray */ 00749 for (j = 0; j < w; j++) 00750 rowbuffer[j] = GET_DATA_BYTE(line, j); 00751 } 00752 else if (colorflg == 1) { /* 8 bpp colormapped */ 00753 for (j = 0; j < w; j++) { 00754 byteval = GET_DATA_BYTE(line, j); 00755 rowbuffer[3 * j + COLOR_RED] = rmap[byteval]; 00756 rowbuffer[3 * j + COLOR_GREEN] = gmap[byteval]; 00757 rowbuffer[3 * j + COLOR_BLUE] = bmap[byteval]; 00758 } 00759 } 00760 else { /* colorflg == 2 */ 00761 if (d == 24) { /* See note 4 above; special case of 24 bpp rgb */ 00762 jpeg_write_scanlines(&cinfo, (JSAMPROW *)&line, 1); 00763 } 00764 else { /* standard 32 bpp rgb */ 00765 ppixel = line; 00766 for (j = k = 0; j < w; j++) { 00767 rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_RED); 00768 rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_GREEN); 00769 rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_BLUE); 00770 ppixel++; 00771 } 00772 } 00773 } 00774 if (d != 24) 00775 jpeg_write_scanlines(&cinfo, &rowbuffer, 1); 00776 } 00777 00778 jpeg_finish_compress(&cinfo); 00779 00780 FREE(rowbuffer); 00781 if (colorflg == 1) { 00782 FREE(rmap); 00783 FREE(gmap); 00784 FREE(bmap); 00785 } 00786 00787 jpeg_destroy_compress(&cinfo); 00788 return 0; 00789 } 00790 00791 00792 /*---------------------------------------------------------------------* 00793 * Read/write to memory * 00794 *---------------------------------------------------------------------*/ 00795 #if HAVE_FMEMOPEN 00796 00797 extern FILE *open_memstream(char **data, size_t *size); 00798 extern FILE *fmemopen(void *data, size_t size, const char *mode); 00799 00800 /*! 00801 * pixReadMemJpeg() 00802 * 00803 * Input: cdata (const; jpeg-encoded) 00804 * size (of data) 00805 * colormap flag (0 means return RGB image if color; 00806 * 1 means create colormap and return 8 bpp 00807 * palette image if color) 00808 * reduction (scaling factor: 1, 2, 4 or 8) 00809 * &pnwarn (<optional return> number of warnings) 00810 * hint (bitwise OR of L_HINT_* values; use 0 for no hint) 00811 * Return: pix, or null on error 00812 * 00813 * Notes: 00814 * (1) The @size byte of @data must be a null character. 00815 * (2) See pixReadJpeg() for usage. 00816 */ 00817 PIX * 00818 pixReadMemJpeg(const l_uint8 *cdata, 00819 size_t size, 00820 l_int32 cmflag, 00821 l_int32 reduction, 00822 l_int32 *pnwarn, 00823 l_int32 hint) 00824 { 00825 l_uint8 *data; 00826 FILE *fp; 00827 PIX *pix; 00828 00829 PROCNAME("pixReadMemJpeg"); 00830 00831 if (!cdata) 00832 return (PIX *)ERROR_PTR("cdata not defined", procName, NULL); 00833 00834 data = (l_uint8 *)cdata; /* we're really not going to change this */ 00835 if ((fp = fmemopen(data, size, "r")) == NULL) 00836 return (PIX *)ERROR_PTR("stream not opened", procName, NULL); 00837 pix = pixReadStreamJpeg(fp, cmflag, reduction, pnwarn, hint); 00838 fclose(fp); 00839 return pix; 00840 } 00841 00842 00843 /*! 00844 * readHeaderMemJpeg() 00845 * 00846 * Input: cdata (const; jpeg-encoded) 00847 * size (of data) 00848 * &w (<optional return>) 00849 * &h (<optional return>) 00850 * &spp (<optional return>, samples/pixel) 00851 * &ycck (<optional return>, 1 if ycck color space; 0 otherwise) 00852 * &cmyk (<optional return>, 1 if cmyk color space; 0 otherwise) 00853 * Return: 0 if OK, 1 on error 00854 */ 00855 l_int32 00856 readHeaderMemJpeg(const l_uint8 *cdata, 00857 size_t size, 00858 l_int32 *pw, 00859 l_int32 *ph, 00860 l_int32 *pspp, 00861 l_int32 *pycck, 00862 l_int32 *pcmyk) 00863 { 00864 l_uint8 *data; 00865 l_int32 ret; 00866 FILE *fp; 00867 00868 PROCNAME("readHeaderMemJpeg"); 00869 00870 if (!cdata) 00871 return ERROR_INT("cdata not defined", procName, 1); 00872 if (!pw && !ph && !pspp && !pycck && !pcmyk) 00873 return ERROR_INT("no results requested", procName, 1); 00874 00875 data = (l_uint8 *)cdata; /* we're really not going to change this */ 00876 if ((fp = fmemopen(data, size, "r")) == NULL) 00877 return ERROR_INT("stream not opened", procName, 1); 00878 ret = freadHeaderJpeg(fp, pw, ph, pspp, pycck, pcmyk); 00879 fclose(fp); 00880 return ret; 00881 } 00882 00883 00884 /*! 00885 * pixWriteMemJpeg() 00886 * 00887 * Input: &data (<return> data of jpeg compressed image) 00888 * &size (<return> size of returned data) 00889 * pix 00890 * quality (1 - 100; 75 is default value; 0 is also default) 00891 * progressive (0 for baseline sequential; 1 for progressive) 00892 * Return: 0 if OK, 1 on error 00893 * 00894 * Notes: 00895 * (1) See pixWriteStreamJpeg() for usage. This version writes to 00896 * memory instead of to a file stream. 00897 */ 00898 l_int32 00899 pixWriteMemJpeg(l_uint8 **pdata, 00900 size_t *psize, 00901 PIX *pix, 00902 l_int32 quality, 00903 l_int32 progressive) 00904 { 00905 l_int32 ret; 00906 FILE *fp; 00907 00908 PROCNAME("pixWriteMemJpeg"); 00909 00910 if (!pdata) 00911 return ERROR_INT("&data not defined", procName, 1 ); 00912 if (!psize) 00913 return ERROR_INT("&size not defined", procName, 1 ); 00914 if (!pix) 00915 return ERROR_INT("&pix not defined", procName, 1 ); 00916 00917 if ((fp = open_memstream((char **)pdata, psize)) == NULL) 00918 return ERROR_INT("stream not opened", procName, 1); 00919 ret = pixWriteStreamJpeg(fp, pix, quality, progressive); 00920 fclose(fp); 00921 return ret; 00922 } 00923 00924 00925 #else /* fmemopen() and open_memstream() are not available */ 00926 00927 00928 /*! 00929 * pixReadMemJpeg() 00930 * 00931 * Input: cdata (const; jpeg-encoded) 00932 * size (of data) 00933 * colormap flag (0 means return RGB image if color; 00934 * 1 means create colormap and return 8 bpp 00935 * palette image if color) 00936 * reduction (scaling factor: 1, 2, 4 or 8) 00937 * &pnwarn (<optional return> number of warnings) 00938 * hint (bitwise OR of L_HINT_* values; use 0 for no hint) 00939 * Return: pix, or null on error 00940 * 00941 * Notes: 00942 * (1) We are cheating here -- writing the data out 00943 * to file in jpeg format and then reading it back. 00944 */ 00945 PIX * 00946 pixReadMemJpeg(const l_uint8 *cdata, 00947 size_t size, 00948 l_int32 cmflag, 00949 l_int32 reduction, 00950 l_int32 *pnwarn, 00951 l_int32 hint) 00952 { 00953 char *tname; 00954 l_uint8 *data; 00955 FILE *fp; 00956 PIX *pix; 00957 00958 PROCNAME("pixReadMemJpeg"); 00959 00960 if (!cdata) 00961 return (PIX *)ERROR_PTR("cdata not defined", procName, NULL); 00962 00963 data = (l_uint8 *)cdata; /* we're really not going to change this */ 00964 tname = genTempFilename("/tmp/", "mem.jpg", 1, 1); 00965 l_binaryWrite(tname, "w", data, size); 00966 if ((fp = fopenReadStream(tname)) == NULL) 00967 return (PIX *)ERROR_PTR("stream not opened", procName, NULL); 00968 pix = pixReadStreamJpeg(fp, cmflag, reduction, pnwarn, hint); 00969 fclose(fp); 00970 remove(tname); 00971 FREE(tname); 00972 if (!pix) 00973 return (PIX *)ERROR_PTR("pix not read", procName, NULL); 00974 return pix; 00975 } 00976 00977 00978 /*! 00979 * readHeaderMemJpeg() 00980 * 00981 * Input: cdata (const; jpeg-encoded) 00982 * size (of data) 00983 * &w (<optional return>) 00984 * &h (<optional return>) 00985 * &spp (<optional return>, samples/pixel) 00986 * &ycck (<optional return>, 1 if ycck color space; 0 otherwise) 00987 * &cmyk (<optional return>, 1 if cmyk color space; 0 otherwise) 00988 * Return: 0 if OK, 1 on error 00989 * 00990 * Notes: 00991 * (1) Parse the jpeg string without without jpeg library calls. 00992 */ 00993 l_int32 00994 readHeaderMemJpeg(const l_uint8 *cdata, 00995 size_t size, 00996 l_int32 *pw, 00997 l_int32 *ph, 00998 l_int32 *pspp, 00999 l_int32 *pycck, 01000 l_int32 *pcmyk) 01001 { 01002 PROCNAME("readHeaderMemJpeg"); 01003 01004 if (!cdata) 01005 return ERROR_INT("cdata not defined", procName, 1); 01006 01007 if (pycck) *pycck = 0; 01008 if (pcmyk) *pcmyk = 0; 01009 return extractJpegDataFromArray(cdata, size, pw, ph, NULL, pspp); 01010 } 01011 01012 01013 /*! 01014 * pixWriteMemJpeg() 01015 * 01016 * Input: &data (<return> data of jpeg compressed image) 01017 * &size (<return> size of returned data) 01018 * pix 01019 * quality (1 - 100; 75 is default value; 0 is also default) 01020 * progressive (0 for baseline sequential; 1 for progressive) 01021 * Return: 0 if OK, 1 on error 01022 * 01023 * Notes: 01024 * (1) We are cheating here -- writing the data out 01025 * to file in jpeg format and then reading it back. 01026 */ 01027 l_int32 01028 pixWriteMemJpeg(l_uint8 **pdata, 01029 size_t *psize, 01030 PIX *pix, 01031 l_int32 quality, 01032 l_int32 progressive) 01033 { 01034 char *tname; 01035 l_uint8 *data; 01036 size_t nbytes; 01037 01038 PROCNAME("pixWriteMemJpeg"); 01039 01040 if (!pdata) 01041 return ERROR_INT("&data not defined", procName, 1 ); 01042 if (!psize) 01043 return ERROR_INT("&size not defined", procName, 1 ); 01044 if (!pix) 01045 return ERROR_INT("&pix not defined", procName, 1 ); 01046 01047 tname = genTempFilename("/tmp/", "mem.jpg", 1, 1); 01048 pixWriteJpeg(tname, pix, quality, progressive); 01049 data = l_binaryRead(tname, &nbytes); 01050 remove(tname); 01051 FREE(tname); 01052 if (!data) 01053 return ERROR_INT("data not returned", procName, 1 ); 01054 *pdata = data; 01055 *psize = nbytes; 01056 return 0; 01057 } 01058 01059 #endif /* HAVE_FMEMOPEN */ 01060 01061 01062 01063 /*---------------------------------------------------------------------* 01064 * Setting special write flag * 01065 *---------------------------------------------------------------------*/ 01066 /*! 01067 * l_jpegSetNoChromaSampling() 01068 * 01069 * Input: flag (0 for standard 2x2 chroma subsampling) 01070 * 1 for no chroma subsampling (high quality)) 01071 * Return: void 01072 */ 01073 void 01074 l_jpegSetNoChromaSampling(l_int32 flag) 01075 { 01076 var_JPEG_NO_CHROMA_SAMPLING = flag; 01077 } 01078 01079 01080 /*---------------------------------------------------------------------* 01081 * Static system helpers * 01082 *---------------------------------------------------------------------*/ 01083 /* The default jpeg error_exit() kills the process. 01084 * We don't want leptonica to allow this to happen. 01085 * If you want this default behavior, remove the 01086 * calls to this in the functions above. */ 01087 static void 01088 jpeg_error_do_not_exit(j_common_ptr cinfo) 01089 { 01090 (*cinfo->err->output_message) (cinfo); 01091 jpeg_destroy(cinfo); 01092 longjmp(jpeg_jmpbuf, 0); 01093 return; 01094 } 01095 01096 /* This function was borrowed from libjpeg. */ 01097 static l_uint8 01098 jpeg_getc(j_decompress_ptr cinfo) 01099 { 01100 struct jpeg_source_mgr *datasrc; 01101 01102 datasrc = cinfo->src; 01103 if (datasrc->bytes_in_buffer == 0) { 01104 if (! (*datasrc->fill_input_buffer) (cinfo)) { 01105 return 0; 01106 } 01107 } 01108 datasrc->bytes_in_buffer--; 01109 return GETJOCTET(*datasrc->next_input_byte++); 01110 } 01111 01112 01113 /* This function is required for reading jpeg comments, and 01114 * was contributed by Antony Dovgal. Why 'boolean'? See 01115 * note above the declaration. */ 01116 static boolean 01117 jpeg_comment_callback(j_decompress_ptr cinfo) 01118 { 01119 l_int32 length, i; 01120 l_uint32 c; 01121 l_uint8 **comment; 01122 01123 comment = (l_uint8 **)cinfo->client_data; 01124 length = jpeg_getc(cinfo) << 8; 01125 length += jpeg_getc(cinfo); 01126 length -= 2; 01127 01128 if (length <= 0) 01129 return 1; 01130 01131 if (*comment) FREE(*comment); 01132 *comment = (l_uint8 *)MALLOC(length + 1); 01133 if (!(*comment)) 01134 return 0; 01135 01136 for (i = 0; i < length; i++) { 01137 c = jpeg_getc(cinfo); 01138 (*comment)[i] = c; 01139 } 01140 (*comment)[length] = 0; 01141 01142 return 1; 01143 } 01144 01145 01146 /*---------------------------------------------------------------------* 01147 * Extraction of jpeg header information by parsing * 01148 *---------------------------------------------------------------------*/ 01149 /*! 01150 * extractJpegDataFromFile() 01151 * 01152 * Input: filein 01153 * &data (<return> binary data consisting of the entire jpeg file) 01154 * &nbytes (<return> size of binary data) 01155 * &w (<optional return> image width) 01156 * &h (<optional return> image height) 01157 * &bps (<optional return> bits/sample; should be 8) 01158 * &spp (<optional return> samples/pixel; should be 1 or 3) 01159 * Return: 0 if OK, 1 on error 01160 */ 01161 l_int32 01162 extractJpegDataFromFile(const char *filein, 01163 l_uint8 **pdata, 01164 size_t *pnbytes, 01165 l_int32 *pw, 01166 l_int32 *ph, 01167 l_int32 *pbps, 01168 l_int32 *pspp) 01169 { 01170 l_uint8 *data; 01171 l_int32 format; 01172 size_t nbytes; 01173 01174 PROCNAME("extractJpegDataFromFile"); 01175 01176 if (!filein) 01177 return ERROR_INT("filein not defined", procName, 1); 01178 if (!pdata) 01179 return ERROR_INT("&data not defined", procName, 1); 01180 if (!pnbytes) 01181 return ERROR_INT("&nbytes not defined", procName, 1); 01182 if (!pw && !ph && !pbps && !pspp) 01183 return ERROR_INT("no output data requested", procName, 1); 01184 *pdata = NULL; 01185 *pnbytes = 0; 01186 01187 findFileFormat(filein, &format); 01188 if (format != IFF_JFIF_JPEG) 01189 return ERROR_INT("filein not jfif jpeg", procName, 1); 01190 01191 if ((data = l_binaryRead(filein, &nbytes)) == NULL) 01192 return ERROR_INT("inarray not made", procName, 1); 01193 *pnbytes = nbytes; 01194 *pdata = data; 01195 01196 /* On error, free the data */ 01197 if (extractJpegDataFromArray(data, nbytes, pw, ph, pbps, pspp)) { 01198 FREE(data); 01199 *pdata = NULL; 01200 *pnbytes = 0; 01201 } 01202 01203 return 0; 01204 } 01205 01206 01207 /*! 01208 * extractJpegDataFromArray() 01209 * 01210 * Input: data (binary data consisting of the entire jpeg file) 01211 * nbytes (size of binary data) 01212 * &w (<optional return> image width) 01213 * &h (<optional return> image height) 01214 * &bps (<optional return> bits/sample; should be 8) 01215 * &spp (<optional return> samples/pixel; should be 1, 3 or 4) 01216 * Return: 0 if OK, 1 on error 01217 */ 01218 l_int32 01219 extractJpegDataFromArray(const void *data, 01220 size_t nbytes, 01221 l_int32 *pw, 01222 l_int32 *ph, 01223 l_int32 *pbps, 01224 l_int32 *pspp) 01225 { 01226 l_uint8 *data8; 01227 l_int32 imeta, msize, bps, w, h, spp; 01228 01229 PROCNAME("extractJpegDataFromArray"); 01230 01231 if (!pw && !ph && !pbps && !pspp) 01232 return ERROR_INT("no output data requested", procName, 1); 01233 if (pw) *pw = 0; 01234 if (ph) *pw = 0; 01235 if (pbps) *pbps = 0; 01236 if (pspp) *pspp = 0; 01237 if (!data) 01238 return ERROR_INT("data not defined", procName, 1); 01239 data8 = (l_uint8 *)data; 01240 01241 /* Find where the image metadata begins in header: 01242 * 0xc0 is start of metadata for baseline DCT; 01243 * 0xc1 is start of metadata for extended sequential DCT; 01244 * ... */ 01245 imeta = 0; 01246 if (locateJpegImageParameters(data8, nbytes, &imeta) == 0) { 01247 /* Save the metadata */ 01248 msize = getTwoByteParameter(data8, imeta); /* metadata size */ 01249 bps = data8[imeta + 2]; 01250 h = getTwoByteParameter(data8, imeta + 3); 01251 w = getTwoByteParameter(data8, imeta + 5); 01252 spp = data8[imeta + 7]; 01253 if (pbps) *pbps = bps; 01254 if (ph) *ph = h; 01255 if (pw) *pw = w; 01256 if (pspp) *pspp = spp; 01257 01258 #if DEBUG_INFO 01259 fprintf(stderr, "w = %d, h = %d, bps = %d, spp = %d\n", w, h, bps, spp); 01260 fprintf(stderr, "imeta = %d, msize = %d\n", imeta, msize); 01261 #endif /* DEBUG_INFO */ 01262 01263 /* Is the data obviously bad? */ 01264 if (h <= 0 || w <= 0 || bps != 8 || (spp != 1 && spp !=3 && spp != 4)) { 01265 L_WARNING("invalid image parameters:", procName); 01266 L_WARNING("fallback to read the entire file", procName); 01267 return extractJpegHeaderDataFallback(data, nbytes, 01268 pw, ph, pbps, pspp); 01269 } 01270 } 01271 else { 01272 L_WARNING("parsing failure; fallback to read entire file", procName); 01273 return extractJpegHeaderDataFallback(data, nbytes, pw, ph, pbps, pspp); 01274 } 01275 01276 return 0; 01277 } 01278 01279 01280 /*! 01281 * extractJpegHeaderDataFallback() 01282 * 01283 * Input: data (binary data consisting of the entire jpeg file) 01284 * nbytes (size of binary data) 01285 * &w (<optional return> image width) 01286 * &h (<optional return> image height) 01287 * &bps (<optional return> bits/sample; should be 8) 01288 * &spp (<optional return> samples/pixel; should be 1 or 3) 01289 * Return: 0 if OK, 1 on error 01290 * 01291 * Notes: 01292 * (1) This gets the header data by uncompressing the jpeg 01293 * data into a pix. It can be used when header parsing fails. 01294 * (2) This cannot distinguish between 3 and 4 spp, so it returns 3. 01295 */ 01296 static l_int32 01297 extractJpegHeaderDataFallback(const void *data, 01298 size_t nbytes, 01299 l_int32 *pw, 01300 l_int32 *ph, 01301 l_int32 *pbps, 01302 l_int32 *pspp) 01303 { 01304 l_uint8 *data8; 01305 l_int32 w, h, d, spp; 01306 PIX *pix; 01307 01308 PROCNAME("extractJpegHeaderDataFallback"); 01309 01310 if (!pw && !ph && !pbps && !pspp) 01311 return ERROR_INT("no output data requested", procName, 1); 01312 if (pw) *pw = 0; 01313 if (ph) *ph = 0; 01314 if (pbps) *pbps = 8; 01315 if (pspp) *pspp = 0; 01316 if (!data) 01317 return ERROR_INT("data not defined", procName, 1); 01318 data8 = (l_uint8 *)data; 01319 01320 if ((pix = pixReadMemJpeg(data8, nbytes, 0, 1, NULL, 0)) == NULL) 01321 return ERROR_INT("unable to read jpeg", procName, 1); 01322 pixGetDimensions(pix, &w, &h, &d); 01323 spp = (d == 8) ? 1 : 3; 01324 if (ph) *ph = h; 01325 if (pw) *pw = w; 01326 if (pspp) *pspp = spp; 01327 pixDestroy(&pix); 01328 return 0; 01329 } 01330 01331 01332 /* 01333 * locateJpegImageParameters() 01334 * 01335 * Input: inarray (binary jpeg) 01336 * size (of the data array) 01337 * &index (<return> location of image metadata) 01338 * Return: 0 if OK, 1 on error. Caller must check this! 01339 * 01340 * Notes: 01341 * (1) The metadata in jpeg files is a mess. There are markers 01342 * for the chunks that are always preceeded by 0xff. 01343 * It is possible to have 0xff in the binary data that is 01344 * not a marker, and this is always 'escaped' by a following 01345 * 0x0 byte. The two bytes following the marker give the 01346 * chunk size, inclusive of those two bytes. The jpeg parser 01347 * runs through the file, looking for special markers such 01348 * as 0xc0 and 0xc2 that indicate the beginning of a metadata 01349 * frame that gives the image size, depth, etc. 01350 * (2) The markers listed here appear to be the only ones that 01351 * we need to worry about. It would have been nice to have 01352 * avoided the switch with all these markers, but 01353 * unfortunately the parser for the jpeg header is set 01354 * to accept any byte marker that's not on the approved list! 01355 * So we have to look for a flag that's not on the list 01356 * (and is not 0 or followed by 0xff), and then interpret 01357 * the size of the data chunk and skip it. Why do this? 01358 * Such a chunk may contain a thumbnail version of the image, 01359 * so if we don't skip it, we will find a pair of bytes such 01360 * as 0xffc0 within the chunk, followed by the metadata 01361 * (e.g., w and h dimensions) for the thumbnail. Not what we want. 01362 * (3) We recently found jpeg files with the sequence 0xffXXff, 01363 * where XX is apparently a random marker not on the 'approved' 01364 * list. These clearly need to be escaped, because there are 01365 * no chunks of size as great as 0xff00 that can be skipped 01366 * (remember: for chunks that must be skipped, the 2 bytes 01367 * after the marker give the chunk size). 01368 * (4) For marker definitions, see, e.g.: 01369 * http://www.digicamsoft.com/itu/itu-t81-36.html 01370 */ 01371 static l_int32 01372 locateJpegImageParameters(l_uint8 *inarray, 01373 size_t size, 01374 l_int32 *pindex) 01375 { 01376 l_uint8 val; 01377 l_int32 index, skiplength; 01378 01379 PROCNAME("locateJpegImageParameters"); 01380 01381 if (!inarray) 01382 return ERROR_INT("inarray not defined", procName, 1); 01383 if (!pindex) 01384 return ERROR_INT("&index not defined", procName, 1); 01385 01386 index = 0; /* start at the beginning of the data */ 01387 while (1) { 01388 if (getNextJpegMarker(inarray, size, &index)) 01389 break; 01390 if ((val = inarray[index]) == 0) /* ignore if "escaped" */ 01391 continue; 01392 if (inarray[index + 1] == 0xff) /* ignore if 'ff' immediately after */ 01393 continue; 01394 /* fprintf(stderr, " marker %x at %o, %d\n", val, index, index); */ 01395 switch(val) 01396 { 01397 /* These are valid metadata start of frame locations */ 01398 case 0xc0: /* M_SOF0 */ 01399 case 0xc1: /* M_SOF1 */ 01400 case 0xc2: /* M_SOF2 */ 01401 case 0xc3: /* M_SOF3 */ 01402 case 0xc5: /* M_SOF5 */ 01403 case 0xc6: /* M_SOF6 */ 01404 case 0xc7: /* M_SOF7 */ 01405 case 0xc9: /* M_SOF9 */ 01406 case 0xca: /* M_SOF10 */ 01407 case 0xcd: /* M_SOF13 */ 01408 case 0xce: /* M_SOF14 */ 01409 case 0xcf: /* M_SOF15 */ 01410 *pindex = index + 1; /* found it */ 01411 return 0; 01412 01413 /* Go on -- these are on the 'approved' list and are 01414 * not chunks that must be skipped */ 01415 case 0x01: /* M_TEM */ 01416 case 0xd0: /* M_RST0 */ 01417 case 0xd1: /* M_RST1 */ 01418 case 0xd2: /* M_RST2 */ 01419 case 0xd3: /* M_RST3 */ 01420 case 0xd4: /* M_RST4 */ 01421 case 0xd5: /* M_RST5 */ 01422 case 0xd6: /* M_RST6 */ 01423 case 0xd7: /* M_RST7 */ 01424 case 0xd8: /* M_SOI */ 01425 case 0xd9: /* M_EOI */ 01426 case 0xe0: /* M_APP0 */ 01427 case 0xee: /* M_APP14 */ 01428 break; 01429 01430 /* Everything else is assumed to be a chunk that must be skipped */ 01431 default: 01432 skiplength = getTwoByteParameter(inarray, index + 1); 01433 /* fprintf(stderr, " skipping: %d bytes at %d\n", 01434 skiplength, index); */ 01435 index += skiplength; 01436 break; 01437 } 01438 } 01439 01440 return 1; /* not found */ 01441 } 01442 01443 01444 /* 01445 * getNextJpegMarker() 01446 * 01447 * Input: array (jpeg data) 01448 * size (from current point to the end) 01449 * &index (input current and <return> the last position searched. 01450 * If it is not at the end of the array, we return 01451 * the first byte that is not 0xff, after 01452 * having encountered at least one 0xff.) 01453 * Return: 0 if a marker is found, 1 if the end of the array is reached 01454 * 01455 * Notes: 01456 * (1) In jpeg, 0xff is used to mark the end of a data segment. 01457 * There may be more than one 0xff in succession. But not every 01458 * 0xff marks the end of a segment. It is possible, though 01459 * rare, that 0xff can occur within some data. In that case, 01460 * the marker is "escaped", by following it with 0x00. 01461 * (2) This function parses a jpeg data stream. It doesn't 01462 * _really_ get the next marker, because it doesn't check if 01463 * the 0xff is escaped. But the caller checks for this escape 01464 * condition, and ignores the marker if escaped. 01465 */ 01466 static l_int32 01467 getNextJpegMarker(l_uint8 *array, 01468 size_t size, 01469 l_int32 *pindex) 01470 { 01471 l_uint8 val; 01472 l_int32 index; 01473 01474 PROCNAME("getNextJpegMarker"); 01475 01476 if (!array) 01477 return ERROR_INT("array not defined", procName, 1); 01478 if (!pindex) 01479 return ERROR_INT("&index not defined", procName, 1); 01480 01481 index = *pindex; /* initial location in array */ 01482 01483 while (index < size) { /* skip to 0xff */ 01484 val = array[index++]; 01485 if (val == 0xff) 01486 break; 01487 } 01488 01489 while (index < size) { /* skip repeated 0xff */ 01490 val = array[index++]; 01491 if (val != 0xff) 01492 break; 01493 } 01494 01495 *pindex = index - 1; 01496 if (index >= size) 01497 return 1; 01498 else 01499 return 0; 01500 } 01501 01502 01503 static l_int32 01504 getTwoByteParameter(l_uint8 *array, 01505 l_int32 index) 01506 { 01507 return (l_int32)((array[index]) << 8) + (l_int32)(array[index + 1]); 01508 } 01509 01510 01511 /* --------------------------------------------*/ 01512 #endif /* HAVE_LIBJPEG */ 01513 /* --------------------------------------------*/