Leptonica 1.68
C Image Processing Library

pnmio.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  *  pnmio.c
00018  *
00019  *      Stream interface
00020  *          PIX             *pixReadStreamPnm()
00021  *          l_int32          readHeaderPnm()
00022  *          l_int32          freadHeaderPnm()
00023  *          l_int32          pixWriteStreamPnm()
00024  *          l_int32          pixWriteStreamAsciiPnm()
00025  *
00026  *      Read/write to memory   [not on windows]
00027  *          PIX             *pixReadMemPnm()
00028  *          l_int32          sreadHeaderPnm()
00029  *          l_int32          pixWriteMemPnm()
00030  *
00031  *      Local helpers
00032  *          static l_int32   pnmReadNextAsciiValue();
00033  *          static l_int32   pnmSkipCommentLines();
00034  *       
00035  *      These are here by popular demand, with the help of Mattias
00036  *      Kregert (mattias@kregert.se), who provided the first implementation.
00037  *
00038  *      The pnm formats are exceedingly simple, because they have
00039  *      no compression and no colormaps.  They support images that
00040  *      are 1 bpp; 2, 4, 8 and 16 bpp grayscale; and rgb.
00041  *
00042  *      The original pnm formats ("ascii") are included for completeness,
00043  *      but their use is deprecated for all but tiny iconic images.
00044  *      They are extremely wasteful of memory; for example, the P1 binary
00045  *      ascii format is 16 times as big as the packed uncompressed
00046  *      format, because 2 characters are used to represent every bit
00047  *      (pixel) in the image.  Reading is slow because we check for extra
00048  *      white space and EOL at every sample value.
00049  * 
00050  *      The packed pnm formats ("raw") give file sizes similar to
00051  *      bmp files, which are uncompressed packed.  However, bmp
00052  *      are more flexible, because they can support colormaps.
00053  *
00054  *      We don't differentiate between the different types ("pbm",
00055  *      "pgm", "ppm") at the interface level, because this is really a
00056  *      "distinction without a difference."  You read a file, you get
00057  *      the appropriate Pix.  You write a file from a Pix, you get the
00058  *      appropriate type of file.  If there is a colormap on the Pix,
00059  *      and the Pix is more than 1 bpp, you get either an 8 bpp pgm
00060  *      or a 24 bpp RGB pnm, depending on whether the colormap colors
00061  *      are gray or rgb, respectively.
00062  *
00063  *      This follows the general policy that the I/O routines don't
00064  *      make decisions about the content of the image -- you do that
00065  *      with image processing before you write it out to file.
00066  *      The I/O routines just try to make the closest connection
00067  *      possible between the file and the Pix in memory.
00068  */
00069 
00070 #include <string.h>
00071 #include "allheaders.h"
00072 
00073 /* --------------------------------------------*/
00074 #if  USE_PNMIO   /* defined in environ.h */
00075 /* --------------------------------------------*/
00076 
00077 
00078 static l_int32 pnmReadNextAsciiValue(FILE  *fp, l_int32 *pval);
00079 static l_int32 pnmSkipCommentLines(FILE  *fp);
00080 
00081     /* a sanity check on the size read from file */
00082 static const l_int32  MAX_PNM_WIDTH = 100000;
00083 static const l_int32  MAX_PNM_HEIGHT = 100000;
00084 
00085 
00086 /*--------------------------------------------------------------------*
00087  *                          Stream interface                          *
00088  *--------------------------------------------------------------------*/
00089 /*!
00090  *  pixReadStreamPnm()
00091  *
00092  *      Input:  stream opened for read
00093  *      Return: pix, or null on error
00094  */
00095 PIX *
00096 pixReadStreamPnm(FILE  *fp)
00097 {
00098 l_uint8    val8, rval8, gval8, bval8;
00099 l_uint16   val16;
00100 l_int32    w, h, d, bpl, wpl, i, j, type;
00101 l_int32    val, rval, gval, bval;
00102 l_uint32   rgbval;
00103 l_uint32  *line, *data;
00104 PIX       *pix;
00105 
00106     PROCNAME("pixReadStreamPnm");
00107 
00108     if (!fp)
00109         return (PIX *)ERROR_PTR("fp not defined", procName, NULL);
00110 
00111     if (freadHeaderPnm(fp, &pix, &w, &h, &d, &type, NULL, NULL))
00112         return (PIX *)ERROR_PTR( "pix not made", procName, NULL);
00113     data = pixGetData(pix);
00114     wpl = pixGetWpl(pix);
00115 
00116         /* Old "ascii" format */
00117     if (type <= 3) {
00118         for (i = 0; i < h; i++) {
00119             for (j = 0; j < w; j++) {
00120                 if (type == 1 || type == 2) {
00121                     if (pnmReadNextAsciiValue(fp, &val))
00122                         return (PIX *)ERROR_PTR( "read abend", procName, pix);
00123                     pixSetPixel(pix, j, i, val);
00124                 }
00125                 else {  /* type == 3 */
00126                     if (pnmReadNextAsciiValue(fp, &rval))
00127                         return (PIX *)ERROR_PTR( "read abend", procName, pix);
00128                     if (pnmReadNextAsciiValue(fp, &gval))
00129                         return (PIX *)ERROR_PTR( "read abend", procName, pix);
00130                     if (pnmReadNextAsciiValue(fp, &bval))
00131                         return (PIX *)ERROR_PTR( "read abend", procName, pix);
00132                     composeRGBPixel(rval, gval, bval, &rgbval);
00133                     pixSetPixel(pix, j, i, rgbval);
00134                 }
00135             }
00136         }
00137         return pix;
00138     }
00139 
00140         /* "raw" format for 1 bpp */
00141     if (type == 4) {
00142         bpl = (d * w + 7) / 8;
00143         for (i = 0; i < h; i++) {
00144             line = data + i * wpl;
00145             for (j = 0; j < bpl; j++) {
00146                 if (fread(&val8, 1, 1, fp) != 1)
00147                     return (PIX *)ERROR_PTR( "read error in 4", procName, pix);
00148                 SET_DATA_BYTE(line, j, val8);
00149             }
00150         }
00151         return pix;
00152     }
00153 
00154         /* "raw" format for grayscale */
00155     if (type == 5) {
00156         bpl = (d * w + 7) / 8;
00157         for (i = 0; i < h; i++) {
00158             line = data + i * wpl;
00159             if (d != 16) {
00160                 for (j = 0; j < w; j++) {
00161                     if (fread(&val8, 1, 1, fp) != 1)
00162                         return (PIX *)ERROR_PTR( "error in 5", procName, pix);
00163                     if (d == 2)
00164                         SET_DATA_DIBIT(line, j, val8);
00165                     else if (d == 4)
00166                         SET_DATA_QBIT(line, j, val8);
00167                     else  /* d == 8 */
00168                         SET_DATA_BYTE(line, j, val8);
00169                 }
00170             }
00171             else {  /* d == 16 */
00172                 for (j = 0; j < w; j++) {
00173                     if (fread(&val16, 2, 1, fp) != 1)
00174                         return (PIX *)ERROR_PTR( "16 bpp error", procName, pix);
00175                     SET_DATA_TWO_BYTES(line, j, val16);
00176                 }
00177             }
00178         }
00179         return pix;
00180     }
00181 
00182         /* "raw" format, type == 6; rgb */
00183     for (i = 0; i < h; i++) {
00184         line = data + i * wpl;
00185         for (j = 0; j < wpl; j++) {
00186             if (fread(&rval8, 1, 1, fp) != 1)
00187                 return (PIX *)ERROR_PTR( "read error type 6", procName, pix);
00188             if (fread(&gval8, 1, 1, fp) != 1)
00189                 return (PIX *)ERROR_PTR( "read error type 6", procName, pix);
00190             if (fread(&bval8, 1, 1, fp) != 1)
00191                 return (PIX *)ERROR_PTR( "read error type 6", procName, pix);
00192             composeRGBPixel(rval8, gval8, bval8, &rgbval);
00193             line[j] = rgbval;
00194         }
00195     }
00196     return pix;
00197 }
00198 
00199 
00200 /*!
00201  *  readHeaderPnm()
00202  *
00203  *      Input:  filename
00204  *              &pix (<optional return> use null to return only header data)
00205  *              &width (<return>)
00206  *              &height (<return>)
00207  *              &depth (<return>)
00208  *              &type (<return> pnm type)
00209  *              &bps (<optional return>, bits/sample)
00210  *              &spp (<optional return>, samples/pixel)
00211  *      Return: 0 if OK, 1 on error
00212  */
00213 l_int32
00214 readHeaderPnm(const char *filename,
00215               PIX     **ppix,
00216               l_int32  *pwidth,
00217               l_int32  *pheight,
00218               l_int32  *pdepth,
00219               l_int32  *ptype,
00220               l_int32  *pbps,
00221               l_int32  *pspp)
00222 {
00223 l_int32  ret;
00224 FILE    *fp;
00225 
00226     PROCNAME("readHeaderPnm");
00227 
00228     if (!filename)
00229         return ERROR_INT("filename not defined", procName, 1);
00230     if (!pwidth || !pheight || !pbps || !pspp)
00231         return ERROR_INT("input ptr(s) not defined", procName, 1);
00232     if ((fp = fopenReadStream(filename)) == NULL)
00233         return ERROR_INT("image file not found", procName, 1);
00234     ret = freadHeaderPnm(fp, ppix, pwidth, pheight, pdepth, ptype, pbps, pspp);
00235     fclose(fp);
00236     return ret;
00237 }
00238 
00239 
00240 /*!
00241  *  freadHeaderPnm()
00242  *
00243  *      Input:  stream opened for read
00244  *              &pix (<optional return> use null to return only header data)
00245  *              &width (<return>)
00246  *              &height (<return>)
00247  *              &depth (<return>)
00248  *              &type (<return> pnm type)
00249  *              &bps (<optional return>, bits/sample)
00250  *              &spp (<optional return>, samples/pixel)
00251  *      Return: 0 if OK, 1 on error
00252  */
00253 l_int32
00254 freadHeaderPnm(FILE     *fp,
00255                PIX     **ppix,
00256                l_int32  *pwidth,
00257                l_int32  *pheight,
00258                l_int32  *pdepth,
00259                l_int32  *ptype,
00260                l_int32  *pbps,
00261                l_int32  *pspp)
00262 {
00263 l_int32  w, h, d, type;
00264 l_int32  maxval;
00265 
00266     PROCNAME("freadHeaderPnm");
00267 
00268     if (!fp)
00269         return ERROR_INT("fp not defined", procName, 1);
00270     if (!pwidth || !pheight || !pdepth || !ptype)
00271         return ERROR_INT("input ptr(s) not defined", procName, 1);
00272 
00273     if (fscanf(fp, "P%d\n", &type) != 1)
00274         return ERROR_INT("invalid read for type", procName, 1);
00275     if (type < 1 || type > 6)
00276         return ERROR_INT("invalid pnm file", procName, 1);
00277 
00278     if (pnmSkipCommentLines(fp))
00279         return ERROR_INT("no data in file", procName, 1);
00280 
00281     if (fscanf(fp, "%d %d\n", &w, &h) != 2)
00282         return ERROR_INT("invalid read for w,h", procName, 1);
00283     if (w <= 0 || h <= 0 || w > MAX_PNM_WIDTH || h > MAX_PNM_HEIGHT)
00284         return ERROR_INT("invalid sizes", procName, 1);
00285 
00286         /* Get depth of pix */
00287     if (type == 1 || type == 4)
00288         d = 1;
00289     else if (type == 2 || type == 5) {
00290         if (fscanf(fp, "%d\n", &maxval) != 1)
00291             return ERROR_INT("invalid read for maxval (2,5)", procName, 1);
00292         if (maxval == 3)
00293             d = 2;
00294         else if (maxval == 15)
00295             d = 4;
00296         else if (maxval == 255)
00297             d = 8;
00298         else if (maxval == 0xffff)
00299             d = 16;
00300         else {
00301             fprintf(stderr, "maxval = %d\n", maxval);
00302             return ERROR_INT("invalid maxval", procName, 1);
00303         }
00304     }
00305     else {  /* type == 3 || type == 6; this is rgb  */
00306         if (fscanf(fp, "%d\n", &maxval) != 1)
00307             return ERROR_INT("invalid read for maxval (3,6)", procName, 1);
00308         if (maxval != 255)
00309             L_WARNING_INT("unexpected maxval = %d", procName, maxval);
00310         d = 32;
00311     }
00312     *pwidth = w;
00313     *pheight = h;
00314     *pdepth = d;
00315     *ptype = type;
00316     if (pbps) *pbps = (d == 32) ? 8 : d;
00317     if (pspp) *pspp = (d == 32) ? 3 : 1;
00318     
00319     if (!ppix)
00320         return 0;
00321 
00322     if ((*ppix = pixCreate(w, h, d)) == NULL)  /* return pix initialized to 0 */
00323         return ERROR_INT( "pix not made", procName, 1);
00324     return 0;
00325 }
00326 
00327 
00328 /*!
00329  *  pixWriteStreamPnm()
00330  *
00331  *      Input:  stream opened for write
00332  *              pix
00333  *      Return: 0 if OK; 1 on error
00334  *
00335  *  Notes:
00336  *      (1) This writes "raw" packed format only:
00337  *          1 bpp --> pbm (P4)
00338  *          2, 4, 8, 16 bpp, no colormap or grayscale colormap --> pgm (P5)
00339  *          2, 4, 8 bpp with color-valued colormap, or rgb --> rgb ppm (P6)
00340  *      (2) 24 bpp rgb are not supported in leptonica, but this will
00341  *          write them out as a packed array of bytes (3 to a pixel).
00342  */
00343 l_int32
00344 pixWriteStreamPnm(FILE  *fp,
00345                   PIX   *pix)
00346 {
00347 l_uint8    val8;
00348 l_uint8    pel[4];
00349 l_uint16   val16;
00350 l_int32    h, w, d, ds, i, j, wpls, bpl, filebpl, writeerror, maxval;
00351 l_uint32  *pword, *datas, *lines;
00352 PIX       *pixs;
00353 
00354     PROCNAME("pixWriteStreamPnm");
00355 
00356     if (!fp)
00357         return ERROR_INT("fp not defined", procName, 1);
00358     if (!pix)
00359         return ERROR_INT("pix not defined", procName, 1);
00360 
00361     pixGetDimensions(pix, &w, &h, &d);
00362     if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 24 && d != 32)
00363         return ERROR_INT("d not in {1,2,4,8,16,24,32}", procName, 1);
00364 
00365         /* If a colormap exists, remove and convert to grayscale or rgb */
00366     if (pixGetColormap(pix) != NULL)
00367         pixs = pixRemoveColormap(pix, REMOVE_CMAP_BASED_ON_SRC);
00368     else
00369         pixs = pixClone(pix);
00370     ds =  pixGetDepth(pixs);
00371     datas = pixGetData(pixs);
00372     wpls = pixGetWpl(pixs);
00373 
00374     writeerror = 0;
00375     if (ds == 1) {  /* binary */
00376         fprintf(fp, "P4\n# Raw PBM file written by leptonica "
00377                     "(www.leptonica.com)\n%d %d\n", w, h);
00378 
00379         bpl = (w + 7) / 8;
00380         for (i = 0; i < h; i++) {
00381             lines = datas + i * wpls;
00382             for (j = 0; j < bpl; j++) {
00383                 val8 = GET_DATA_BYTE(lines, j);
00384                 fwrite(&val8, 1, 1, fp);
00385             }
00386         }
00387     }
00388     else if (ds == 2 || ds == 4 || ds == 8 || ds == 16) {  /* grayscale */
00389         maxval = (1 << ds) - 1;
00390         fprintf(fp, "P5\n# Raw PGM file written by leptonica "
00391                     "(www.leptonica.com)\n%d %d\n%d\n", w, h, maxval);
00392 
00393         if (ds != 16) {
00394             for (i = 0; i < h; i++) {
00395                 lines = datas + i * wpls;
00396                 for (j = 0; j < w; j++) {
00397                     if (ds == 2)
00398                         val8 = GET_DATA_DIBIT(lines, j);
00399                     else if (ds == 4)
00400                         val8 = GET_DATA_QBIT(lines, j);
00401                     else  /* ds == 8 */
00402                         val8 = GET_DATA_BYTE(lines, j);
00403                     fwrite(&val8, 1, 1, fp);
00404                 }
00405             }
00406         }
00407         else {  /* ds == 16 */
00408             for (i = 0; i < h; i++) {
00409                 lines = datas + i * wpls;
00410                 for (j = 0; j < w; j++) {
00411                     val16 = GET_DATA_TWO_BYTES(lines, j);
00412                     fwrite(&val16, 2, 1, fp);
00413                 }
00414             }
00415         }
00416     }
00417     else {  /* rgb color */
00418         fprintf(fp, "P6\n# Raw PPM file written by leptonica "
00419                     "(www.leptonica.com)\n%d %d\n255\n", w, h);
00420 
00421         if (d == 24) {   /* packed, 3 bytes to a pixel */
00422             filebpl = 3 * w;
00423             for (i = 0; i < h; i++) {  /* write out each raster line */
00424                 lines = datas + i * wpls;
00425                 if (fwrite(lines, 1, filebpl, fp) != filebpl)
00426                     writeerror = 1;
00427             }
00428         }
00429         else {  /* 32 bpp rgb */
00430             for (i = 0; i < h; i++) {
00431                 lines = datas + i * wpls;
00432                 for (j = 0; j < wpls; j++) {
00433                     pword = lines + j;
00434                     pel[0] = *((l_uint8 *)pword + 3);   /* red   */
00435                     pel[1] = *((l_uint8 *)pword + 2);   /* green */
00436                     pel[2] = *((l_uint8 *)pword + 1);   /* blue  */
00437                     if (fwrite(&pel, 1, 3, fp) != 3)
00438                         writeerror = 1;
00439                 }
00440             }
00441         }
00442     }
00443 
00444     pixDestroy(&pixs);
00445     if (writeerror)
00446         return ERROR_INT("image write fail", procName, 1);
00447     return 0;
00448 }
00449 
00450 
00451 /*!
00452  *  pixWriteStreamAsciiPnm()
00453  *
00454  *      Input:  stream opened for write
00455  *              pix
00456  *      Return: 0 if OK; 1 on error
00457  *
00458  *  Writes "ascii" format only:
00459  *      1 bpp --> pbm (P1)
00460  *      2, 4, 8, 16 bpp, no colormap or grayscale colormap --> pgm (P2)
00461  *      2, 4, 8 bpp with color-valued colormap, or rgb --> rgb ppm (P3)
00462  */
00463 l_int32
00464 pixWriteStreamAsciiPnm(FILE  *fp,
00465                        PIX   *pix)
00466 {
00467 char       buffer[256];
00468 l_uint8    cval[3];
00469 l_int32    h, w, d, ds, i, j, k, maxval, count;
00470 l_uint32   val;
00471 PIX       *pixs;
00472 
00473     PROCNAME("pixWriteStreamAsciiPnm");
00474 
00475     if (!fp)
00476         return ERROR_INT("fp not defined", procName, 1);
00477     if (!pix)
00478         return ERROR_INT("pix not defined", procName, 1);
00479 
00480     pixGetDimensions(pix, &w, &h, &d);
00481     if (d != 1 && d != 2 && d != 4 && d != 8 && d != 16 && d != 32)
00482         return ERROR_INT("d not in {1,2,4,8,16,32}", procName, 1);
00483 
00484         /* If a colormap exists, remove and convert to grayscale or rgb */
00485     if (pixGetColormap(pix) != NULL)
00486         pixs = pixRemoveColormap(pix, REMOVE_CMAP_BASED_ON_SRC);
00487     else
00488         pixs = pixClone(pix);
00489     ds =  pixGetDepth(pixs);
00490 
00491     if (ds == 1) {  /* binary */
00492         fprintf(fp, "P1\n# Ascii PBM file written by leptonica "
00493                     "(www.leptonica.com)\n%d %d\n", w, h);
00494 
00495         count = 0;
00496         for (i = 0; i < h; i++) {
00497             for (j = 0; j < w; j++) {
00498                 pixGetPixel(pixs, j, i, &val);
00499                 if (val == 0)
00500                     fputc('0', fp);
00501                 else  /* val == 1 */
00502                     fputc('1', fp);
00503                 fputc(' ', fp);
00504                 count += 2;
00505                 if (count >= 70)
00506                     fputc('\n', fp);
00507             }
00508         }
00509     }
00510     else if (ds == 2 || ds == 4 || ds == 8 || ds == 16) {  /* grayscale */
00511         maxval = (1 << ds) - 1;
00512         fprintf(fp, "P2\n# Ascii PGM file written by leptonica "
00513                     "(www.leptonica.com)\n%d %d\n%d\n", w, h, maxval);
00514 
00515         count = 0;
00516         for (i = 0; i < h; i++) {
00517             for (j = 0; j < w; j++) {
00518                 pixGetPixel(pixs, j, i, &val);
00519                 if (ds == 2) {
00520                     sprintf(buffer, "%1d ", val);
00521                     fwrite(buffer, 1, 2, fp);
00522                     count += 2;
00523                 }
00524                 else if (ds == 4) {
00525                     sprintf(buffer, "%2d ", val);
00526                     fwrite(buffer, 1, 3, fp);
00527                     count += 3;
00528                 }
00529                 else if (ds == 8) {
00530                     sprintf(buffer, "%3d ", val);
00531                     fwrite(buffer, 1, 4, fp);
00532                     count += 4;
00533                 }
00534                 else {  /* ds == 16 */
00535                     sprintf(buffer, "%5d ", val);
00536                     fwrite(buffer, 1, 6, fp);
00537                     count += 6;
00538                 }
00539                 if (count >= 60) {
00540                     fputc('\n', fp);
00541                     count = 0;
00542                 }
00543             }
00544         }
00545     }
00546     else {  /* rgb color */
00547         fprintf(fp, "P3\n# Ascii PPM file written by leptonica "
00548                     "(www.leptonica.com)\n%d %d\n255\n", w, h);
00549 
00550         count = 0;
00551         for (i = 0; i < h; i++) {
00552             for (j = 0; j < w; j++) {
00553                 pixGetPixel(pixs, j, i, &val);
00554                 cval[0] = GET_DATA_BYTE(&val, COLOR_RED);
00555                 cval[1] = GET_DATA_BYTE(&val, COLOR_GREEN);
00556                 cval[2] = GET_DATA_BYTE(&val, COLOR_BLUE);
00557                 for (k = 0; k < 3; k++) {
00558                     sprintf(buffer, "%3d ", cval[k]);
00559                     fwrite(buffer, 1, 4, fp);
00560                     count += 4;
00561                     if (count >= 60) {
00562                         fputc('\n', fp);
00563                         count = 0;
00564                     }
00565                 }
00566             }
00567         }
00568     }
00569 
00570     pixDestroy(&pixs);
00571     return 0;
00572 }
00573 
00574 
00575 /*---------------------------------------------------------------------*
00576  *                         Read/write to memory                        *
00577  *---------------------------------------------------------------------*/
00578 #ifdef HAVE_CONFIG_H
00579 #include "config_auto.h"
00580 #endif  /* HAVE_CONFIG_H */
00581 
00582 #if HAVE_FMEMOPEN
00583 
00584 extern FILE *open_memstream(char **data, size_t *size);
00585 extern FILE *fmemopen(void *data, size_t size, const char *mode);
00586 
00587 /*!
00588  *  pixReadMemPnm()
00589  *
00590  *      Input:  cdata (const; pnm-encoded)
00591  *              size (of data)
00592  *      Return: pix, or null on error
00593  *
00594  *  Notes:
00595  *      (1) The @size byte of @data must be a null character.
00596  */
00597 PIX *
00598 pixReadMemPnm(const l_uint8  *cdata,
00599               size_t          size)
00600 {
00601 l_uint8  *data;
00602 FILE     *fp;
00603 PIX      *pix;
00604 
00605     PROCNAME("pixReadMemPnm");
00606 
00607     if (!cdata)
00608         return (PIX *)ERROR_PTR("cdata not defined", procName, NULL);
00609 
00610     data = (l_uint8 *)cdata;  /* we're really not going to change this */
00611     if ((fp = fmemopen(data, size, "r")) == NULL)
00612         return (PIX *)ERROR_PTR("stream not opened", procName, NULL);
00613     pix = pixReadStreamPnm(fp);
00614     fclose(fp);
00615     return pix;
00616 }
00617 
00618 
00619 /*!
00620  *  sreadHeaderPnm()
00621  *
00622  *      Input:  cdata (const; pnm-encoded)
00623  *              size (of data)
00624  *              &width (<return>)
00625  *              &height (<return>)
00626  *              &depth (<return>)
00627  *              &type (<return> pnm type)
00628  *              &bps (<optional return>, bits/sample)
00629  *              &spp (<optional return>, samples/pixel)
00630  *      Return: 0 if OK, 1 on error
00631  */
00632 l_int32
00633 sreadHeaderPnm(const l_uint8  *cdata,
00634                size_t          size,
00635                l_int32        *pwidth,
00636                l_int32        *pheight,
00637                l_int32        *pdepth,
00638                l_int32        *ptype,
00639                l_int32        *pbps,
00640                l_int32        *pspp)
00641 {
00642 l_int32   ret;
00643 l_uint8  *data;
00644 FILE     *fp;
00645 
00646     PROCNAME("sreadHeaderPnm");
00647 
00648     if (!cdata)
00649         return ERROR_INT("cdata not defined", procName, 1);
00650 
00651     data = (l_uint8 *)cdata;  /* we're really not going to change this */
00652     if ((fp = fmemopen(data, size, "r")) == NULL)
00653         return ERROR_INT("stream not opened", procName, 1);
00654     ret = freadHeaderPnm(fp, NULL, pwidth, pheight, pdepth, ptype, pbps, pspp);
00655     fclose(fp);
00656     if (ret)
00657         return ERROR_INT("header data read failed", procName, 1);
00658     return 0;
00659 }
00660 
00661 
00662 /*!
00663  *  pixWriteMemPnm()
00664  *
00665  *      Input:  &data (<return> data of tiff compressed image)
00666  *              &size (<return> size of returned data)
00667  *              pix
00668  *      Return: 0 if OK, 1 on error
00669  *
00670  *  Notes:
00671  *      (1) See pixWriteStreamPnm() for usage.  This version writes to
00672  *          memory instead of to a file stream.
00673  */
00674 l_int32
00675 pixWriteMemPnm(l_uint8  **pdata,
00676                size_t    *psize,
00677                PIX       *pix)
00678 {
00679 l_int32  ret;
00680 FILE    *fp;
00681 
00682     PROCNAME("pixWriteMemPnm");
00683 
00684     if (!pdata)
00685         return ERROR_INT("&data not defined", procName, 1 );
00686     if (!psize)
00687         return ERROR_INT("&size not defined", procName, 1 );
00688     if (!pix)
00689         return ERROR_INT("&pix not defined", procName, 1 );
00690 
00691     if ((fp = open_memstream((char **)pdata, psize)) == NULL)
00692         return ERROR_INT("stream not opened", procName, 1);
00693     ret = pixWriteStreamPnm(fp, pix);
00694     fclose(fp);
00695     return ret;
00696 }
00697 
00698 #else
00699 
00700 PIX *
00701 pixReadMemPnm(const l_uint8  *cdata,
00702               size_t          size)
00703 {
00704     return (PIX *)ERROR_PTR(
00705         "pnm read from memory not implemented on this platform",
00706         "pixReadMemPnm", NULL);
00707 }
00708 
00709 
00710 l_int32
00711 sreadHeaderPnm(const l_uint8  *cdata,
00712                size_t          size,
00713                l_int32        *pwidth,
00714                l_int32        *pheight,
00715                l_int32        *pdepth,
00716                l_int32        *ptype,
00717                l_int32        *pbps,
00718                l_int32        *pspp)
00719 {
00720     return ERROR_INT(
00721         "pnm read header from memory not implemented on this platform",
00722         "sreadHeaderPnm", 1);
00723 }
00724 
00725 
00726 l_int32
00727 pixWriteMemPnm(l_uint8  **pdata,
00728                size_t    *psize,
00729                PIX       *pix)
00730 {
00731     return ERROR_INT(
00732         "pnm write to memory not implemented on this platform",
00733         "pixWriteMemPnm", 1);
00734 }
00735 
00736 #endif  /* HAVE_FMEMOPEN */
00737 
00738 
00739 /*--------------------------------------------------------------------*
00740  *                          Static helpers                            *
00741  *--------------------------------------------------------------------*/
00742 /*!
00743  *  pnmReadNextAsciiValue()
00744  *
00745  *      Return: 0 if OK, 1 on error or EOF.
00746  *
00747  *  Notes:
00748  *      (1) This reads the next sample value in ascii from the the file.
00749  */
00750 static l_int32
00751 pnmReadNextAsciiValue(FILE  *fp,
00752                       l_int32 *pval)
00753 {
00754 l_int32   c, ignore;
00755 
00756     PROCNAME("pnmReadNextAsciiValue");
00757 
00758     if (!fp)
00759         return ERROR_INT("stream not open", procName, 1);
00760     if (!pval)
00761         return ERROR_INT("&val not defined", procName, 1);
00762     *pval = 0;
00763     do {  /* skip whitespace */
00764         if ((c = fgetc(fp)) == EOF)
00765             return 1;
00766     } while (c == ' ' || c == '\t' || c == '\n' || c == '\r');
00767 
00768     fseek(fp, -1L, SEEK_CUR);        /* back up one byte */
00769     ignore = fscanf(fp, "%d", pval);
00770     return 0;
00771 }
00772 
00773 
00774 /*!
00775  *  pnmSkipCommentLines()
00776  *
00777  *      Return: 0 if OK, 1 on error or EOF
00778  *
00779  *  Notes:
00780  *      (1) Comment lines begin with '#'
00781  *      (2) Usage: caller should check return value for EOF
00782  */
00783 static l_int32 
00784 pnmSkipCommentLines(FILE  *fp)
00785 {
00786 l_int32  c;
00787 
00788     PROCNAME("pnmSkipCommentLines");
00789 
00790     if (!fp)
00791         return ERROR_INT("stream not open", procName, 1);
00792     if ((c = fgetc(fp)) == EOF)
00793         return 1;
00794     if (c == '#') {
00795         do {  /* each line starting with '#' */
00796             do {  /* this entire line */
00797                 if ((c = fgetc(fp)) == EOF)
00798                     return 1;
00799             } while (c != '\n');
00800             if ((c = fgetc(fp)) == EOF)
00801                 return 1;
00802         } while (c == '#');
00803     }
00804 
00805         /* Back up one byte */
00806     fseek(fp, -1L, SEEK_CUR);
00807     return 0;
00808 }
00809 
00810 /* --------------------------------------------*/
00811 #endif  /* USE_PNMIO */
00812 /* --------------------------------------------*/
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines