Leptonica 1.68
C Image Processing Library

jpegio.c

Go to the documentation of this file.
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 /* --------------------------------------------*/
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines