Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

ImagePPM.c

Go to the documentation of this file.
00001 /* ---------------------------------------------------------------------------
00002     Phission : 
00003         Realtime Vision Processing System
00004     
00005     Copyright (C) 2003-2006 Philip D.S. Thoren (pthoren@cs.uml.edu)
00006     University of Massachusetts at Lowell,
00007     Laboratory for Artificial Intelligence and Robotics
00008     
00009     This file is part of Phission.
00010 
00011     Phission is free software; you can redistribute it and/or modify
00012     it under the terms of the GNU Lesser General Public License as published by
00013     the Free Software Foundation; either version 2 of the License, or
00014     (at your option) any later version.
00015 
00016     Phission is distributed in the hope that it will be useful,
00017     but WITHOUT ANY WARRANTY; without even the implied warranty of
00018     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019     GNU Lesser General Public License for more details.
00020 
00021     You should have received a copy of the GNU Lesser General Public License
00022     along with Phission; if not, write to the Free Software
00023     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00024 
00025  ---------------------------------------------------------------------------*/
00026 
00027 /* ----------------------------------------------------------------------------
00028  * phFilePPM.c -- Portable Pixmap image library
00029  * ----------------------------------------------------------------------------
00030  * John R. Watson (jwatson@cs.uml.edu)
00031  * 91.549 Robotics II, Vision Project 1
00032  * DUE 11/13/03
00033  * ----------------------------------------------------------------------------
00034  * This code is part of IPL, and is released under version 2 of the GPL.
00035  * Copyright (c) 2003 John R. Watson.  See README and COPYING for more
00036  * information.
00037  * ----------------------------------------------------------------------------
00038  * This is a libary for reading & writing PPM files
00039  */
00040 #ifdef HAVE_CONFIG_H
00041     #include <phissionconfig.h>
00042 #endif
00043 
00044 #include <phStandard.h>
00045 
00046 #if defined(HAVE_ERRNO_H)
00047     #include <errno.h>
00048 #endif
00049 
00050 #include <phError.h>
00051 #include <phMemory.h>
00052 #include <phPrint.h>
00053 
00054 #include <ImagePPM.h>
00055 
00056 #ifdef __cplusplus
00057 extern "C" {
00058 #endif /* __cplusplus */
00059     
00060 /* ------------------------------------------------------------------------- */
00061 struct ph_ppm_image_s 
00062 {
00063     uint8_t *_mem;          /* memory pool (private)            */
00064     uint8_t *data;          /* image data                       */
00065     int maxval;             /* maximum color value              */
00066     int _len;               /* image length, w * h * 3(private) */
00067     int w;                  /* image width                      */
00068     int h;                  /* image height                     */
00069 };
00070 
00071 /* ------------------------------------------------------------------------- */
00072 # if 0
00073 static void ph_ppm__read_line(FILE *fp, char *buf, int len)
00074 {
00075     int done = 0;
00076 
00077     /* comments are lines that start before the maxval line in the
00078      * header, and begin with a '#'.  keep reading until we encounter a
00079      * line that is not a comment
00080      */
00081     while (!done)
00082     {
00083         fgets((char*)buf, len, fp);
00084         if (*buf == '#')
00085             continue;
00086 
00087         done++;
00088     }
00089 }
00090 #endif /* #if 0 */
00091 
00092 /* ------------------------------------------------------------------------- */
00093 static void ph_ppm__skip_pastchar(FILE *fp, char ch )
00094 {
00095     int c           = 0;
00096     int done        = 0;
00097 
00098     /* Make sure we don't start on whitespace */
00099     while (!done)
00100     {
00101         c = fgetc(fp);
00102         if (ch == c) done = 1;
00103     }
00104 }
00105 
00106 /* ------------------------------------------------------------------------- */
00107 static int ph_ppm__skip_whitespace(FILE *fp)
00108 {
00109     int newline_wait= 0;
00110     int rc          = 0;
00111     int c           = 0;
00112     int done        = 0;
00113     int i = 0;
00114 
00115     /* Make sure we don't start on whitespace */
00116     while (!done)
00117     {
00118         c = fgetc(fp);
00119         switch (c)
00120         {
00121             case ' ':
00122             case '\t':
00123             case '\r':
00124                 break;
00125             case '\n':
00126                 if (newline_wait == 1)
00127                 {
00128                     newline_wait = 0;
00129                     //done = 1;
00130                 }
00131                 break;
00132             case '#':
00133                 newline_wait = 1;
00134                 break;
00135             default:
00136                 if (newline_wait != 1) done = 1;
00137                 /* We need to move the pointer back 1 space because it's the character
00138                  * that broke us out of the loop above and is a valid field value */
00139 
00140                 break;
00141         }
00142     }
00143 #if 1
00144     rc = fseek(fp,-1L,SEEK_CUR);
00145     if (rc < 0)
00146     {
00147         perror("fseek");
00148         return -1;
00149     }
00150 #else
00151     rc = ungetc(c,fp);
00152     if (rc < 0)
00153     {
00154         perror("ungetc");
00155         return -1;
00156     }
00157 #endif
00158 
00159     return 0;
00160 }
00161 
00162 /* ----------------------------------------------------------------------------
00163  * Returns the number of characters read
00164  * Returns -1 on error
00165  * Reads at most len-1 characters and puts a NULL byte (\0) in the last byte
00166  * ------------------------------------------------------------------------- */
00167 static int ph_ppm__read_field(FILE *fp, char *buf, int len)
00168 {
00169     phFUNCTION("ph_ppm__read_field")
00170     int c   = 0;
00171     int i   = 0;
00172     int done= 0;
00173 
00174     rc = ph_ppm__skip_whitespace(fp);
00175     if (rc < 0)
00176     {
00177         phERROR_PRINT(NULL,"ph_ppm__skip_whitespace failed.");
00178         return -1;
00179     }
00180 
00181     /* comments are lines that start before the maxval line in the
00182      * header, and begin with a '#'.  keep reading until we encounter a
00183      * line that is not a comment */
00184     
00185     /* We're not starting on whitespace or a commented part of the input
00186      * so we don't need to parse comments */
00187     while ((!done) && (i < (len-1)))
00188     {
00189         c = fgetc(fp);
00190         
00191         switch (c)
00192         {
00193             case ' ':
00194             case '\t':
00195             case '\r':
00196             case '#':
00197             case '\n':
00198                 /* Put the character back since we're not using it */
00199 #if 1
00200                 rc = fseek(fp,-1,SEEK_CUR);
00201                 if (rc < 0)
00202                 {
00203                     perror("fseek");
00204                     return -1;
00205                 }
00206 #else
00207                 rc = ungetc(c,fp);
00208                 if (rc < 0)
00209                 {
00210                     perror("ungetc");
00211                     return -1;
00212                 }
00213 #endif
00214                 done = 1;
00215                 break;
00216 
00217             default:
00218                 /* save the valid character */
00219                 
00220                 buf[i++] = c;
00221                 break;
00222         }
00223     }
00224 
00225     /* Put a NULL byte at the end of the line */
00226     buf[i] = '\0';
00227 
00228     return i;
00229 }
00230 
00231 /* ----------------------------------------------------------------------------
00232  * ------------------------------------------------------------------------- */
00233 static int ph_ppm__parse_header(FILE *fp, phPPM_image ppm)
00234 {
00235     phFUNCTION("ph_ppm__parse_header")
00236     char buf[20];
00237     
00238     /* read in the magic number */
00239     rc = ph_ppm__read_field(fp, buf, 10);
00240     if (rc < 0)
00241     {
00242         phERROR_PRINT(NULL,"ph_ppm__read_field failed.");
00243         return -1;
00244     }
00245     if (strncmp(buf, "P6", 2) != 0)
00246     {
00247         phERROR_PRINT(NULL,"file is not a valid PPM");
00248         return -1;
00249     }
00250 
00251     /* read in the width */
00252     rc = ph_ppm__read_field(fp, buf, 10);
00253     if (rc < 0)
00254     {
00255         phERROR_PRINT(NULL,"ph_ppm__read_field failed.");
00256         return -1;
00257     }
00258 
00259     /* convert the width */
00260     ppm->w = atoi(buf);
00261     if (ppm->w < 0)
00262     {
00263         phERROR_PRINT(NULL,"atoi returned %d for width",ppm->w );
00264         ppm->w = 0;
00265         return -1;
00266     }
00267 
00268     /* read in the height */
00269     rc = ph_ppm__read_field(fp, buf, 10);
00270     if (rc < 0)
00271     {
00272         phERROR_PRINT(NULL,"ph_ppm__read_field failed.");
00273         return -1;
00274     }
00275 
00276     /* convert the height */
00277     ppm->h = atoi(buf);
00278     if (ppm->h < 0)
00279     {
00280         phERROR_PRINT(NULL,"atoi returned %d for height",ppm->h );
00281         ppm->h = 0;
00282         return -1;
00283     }
00284 
00285     /* PPMs are RGB, so we have 24 bpp */
00286     ppm->_len = ppm->w * ppm->h * 3;
00287 
00288     /* read in the maximum gray value */
00289     rc = ph_ppm__read_field(fp, buf, 10);
00290     if (rc < 0)
00291     {
00292         phERROR_PRINT(NULL,"ph_ppm__read_field failed.");
00293         return -1;
00294     }
00295     
00296     /* Convert the maximum gray value */
00297     ppm->maxval = atoi(buf);
00298     if (ppm->maxval < 0)
00299     {
00300         phERROR_PRINT(NULL,"atoi returned %d for maxval",ppm->maxval );
00301         ppm->maxval = 0;
00302         return -1;
00303     }
00304 
00305     /* according to the PPM spec, the maximum gray value must be < 65536,
00306      * which would be a 16-bit image.  We're only going to support 8-bit
00307      * images, and thus will impose a limit of 256
00308      */
00309     if (ppm->maxval > 255)
00310     {
00311         phERROR_PRINT(NULL,"file is not a valid 8-bit PPM");
00312         return -2;
00313     }
00314 
00315 
00316     /* Skip to the next newline */
00317     ph_ppm__skip_pastchar(fp,'\n');
00318 
00319     return 0;
00320 }
00321 
00322 /* ----------------------------------------------------------------------------
00323  * ------------------------------------------------------------------------- */
00324 int ph_ppm_create_raw(phPPM_image *ppm, uint8_t *data, const int w, const int h)
00325 {
00326     phFUNCTION("ph_ppm_create_raw")
00327     int n;
00328     phPPM_image ppmimg = NULL;
00329     
00330     /* do some sanity checking */
00331     if (data == NULL)
00332     {
00333         phERROR_PRINT(NULL,"pointer to RAW data is NULL");
00334         return 1;
00335     }
00336     
00337     if (w < 1 || h < 1)
00338     {
00339         phERROR_PRINT(NULL,"invalid image dimensions: %dx%d", w, h);
00340         return -2;
00341     }
00342     
00343     /* allocate a new image object */
00344     *ppm = NULL;
00345     ppmimg = *ppm = (phPPM_image)phCalloc(1, sizeof(struct ph_ppm_image_s));
00346     if (*ppm == NULL)
00347     {
00348         phERROR_PRINT("phCalloc","phCalloc() failed" );
00349         return -3;
00350     }
00351 
00352     /* fill in our PPM object */
00353     ppmimg->w    = w;
00354     ppmimg->h    = h;
00355     ppmimg->_len = w * h * 3;
00356     ppmimg->data = data;
00357 
00358     /* find the maxval in the data.  maxval was implicitly initialized to
00359      * 0 by phCalloc()
00360      */
00361     ppmimg->maxval = 1;
00362     for (n=0; n<ppmimg->_len; n++)
00363     {
00364         if (ppmimg->maxval == 255)
00365             break;
00366         
00367         if (data[n] > ppmimg->maxval)
00368             ppmimg->maxval = data[n];
00369     }
00370 
00371     return 0;
00372 }
00373 
00374 /* ----------------------------------------------------------------------------
00375  * ------------------------------------------------------------------------- */
00376 int ph_ppm_load(phPPM_image *ppm, const char *file)
00377 {
00378     phFUNCTION("ph_ppm_load")
00379     FILE        *fp         = NULL;
00380     uint32_t     data_left  = 0;
00381     uint8_t     *ptr        = NULL;
00382     
00383 #if HAVE_FOPEN
00384     /* allocate a new image object */
00385     *ppm = NULL;
00386     *ppm = (phPPM_image)phCalloc(1, sizeof(struct ph_ppm_image_s));
00387     if (*ppm == NULL)
00388     {
00389         phERROR_PRINT("phCalloc","phCalloc() failed");
00390         return -1;
00391     }
00392     
00393     /* open the file */
00394     fp = fopen(file, "rb");
00395     if (fp == NULL)
00396     {
00397         phERROR_PRINT("fopen","fopen(%s,\"rb\") failed", file );
00398         return -2;
00399     }
00400 
00401     /* parse the PPM header */
00402     rc = ph_ppm__parse_header(fp, *ppm);
00403     if (rc < 0)
00404     {
00405         phERROR_PRINT(NULL,"ph_ppm__parse_header() failed");
00406         return -3;
00407     }
00408 
00409     /* allocate space for the image data, plus 15 bytes for alignment */
00410     (*ppm)->_mem = (uint8_t*)phCalloc((*ppm)->_len + 15, sizeof(uint8_t));
00411     if ((*ppm)->_mem == NULL)
00412     {
00413         phERROR_PRINT("phCalloc","phCalloc() failed");
00414         return -4;
00415     }
00416 
00417     /* align the data pointer on a 16-byte boundary */
00418     (*ppm)->data = (*ppm)->_mem + (*((*ppm)->_mem) & 15);
00419 
00420     //phPRINT("ftell returned : %u\n",ftell(fp));
00421 
00422     /* read in the image data */
00423     data_left   = (*ppm)->_len;
00424     ptr         = (*ppm)->data;
00425     do 
00426     {
00427         rc = fread(ptr, 1, data_left, fp);
00428         if (rc <= 0)
00429         {
00430             phERROR_PRINT(NULL,"%d = fread(%p,1,%d,%p) failed", 
00431                         rc, ptr, data_left, fp );
00432             return -5;
00433         }
00434 
00435         if (rc > 0)
00436         {
00437             data_left -= rc;
00438             ptr       += rc;
00439         }
00440     }
00441     while ((data_left > 0) && (rc > 0));
00442     
00443     fclose(fp);
00444     
00445     return 0;
00446 #else
00447     return -1;
00448 #endif
00449 }
00450 
00451 /* ----------------------------------------------------------------------------
00452  * ------------------------------------------------------------------------- */
00453 int ph_ppm_save(const phPPM_image ppm, const char *file)
00454 {
00455     phFUNCTION("ph_ppm_save")
00456     FILE        *fp         = NULL;
00457     uint32_t     data_left  = 0;
00458     uint8_t     *ptr        = NULL;
00459 
00460 #if HAVE_FOPEN
00461     /* open the output file */
00462     fp = fopen(file, "wb");
00463     if (fp == NULL)
00464     {
00465         phERROR_PRINT("fopen","fopen(%s, \"wb\") failed",file);
00466         return -1;
00467     }
00468 
00469     /* write the PPM header */
00470     fprintf(fp, "P6\n%d %d\n%d\n", ppm->w, ppm->h, ppm->maxval);
00471 
00472     data_left = ppm->_len;
00473     ptr = ppm->data;
00474     do
00475     {
00476         /* write the image data */
00477         rc = fwrite(ptr, 1, data_left, fp);
00478         if (rc <= 0)
00479         {
00480             phERROR_PRINT("fwrite","fwrite(%p,1,%u,%p) failed",
00481                           ptr,data_left,fp);
00482             return -2;
00483         }
00484         if (rc > 0) 
00485         {
00486             data_left -= rc;
00487             ptr += rc;
00488         }
00489     }
00490     while ((data_left > 0) && (rc > 0));
00491 
00492     fclose(fp);
00493 
00494     return 0;
00495 #else
00496     return -1;
00497 #endif
00498 }
00499 
00500 /* ----------------------------------------------------------------------------
00501  * ------------------------------------------------------------------------- */
00502 void ph_ppm_destroy(phPPM_image *ppm)
00503 {
00504     if (*ppm == NULL)
00505         return;
00506 
00507     if ((*ppm)->_mem != NULL)
00508     {
00509         phMemset((*ppm)->_mem, 0, (*ppm)->_len + 15);
00510         free((*ppm)->_mem);
00511     }
00512 
00513     phMemset(*ppm, 0, sizeof(struct ph_ppm_image_s));
00514     free(*ppm);
00515     *ppm = NULL;
00516 }
00517 
00518 /* ----------------------------------------------------------------------------
00519  * ------------------------------------------------------------------------- */
00520 int ph_ppm_get_width(const phPPM_image ppm)
00521 {
00522     return ppm->w;
00523 }
00524 
00525 /* ----------------------------------------------------------------------------
00526  * ------------------------------------------------------------------------- */
00527 int ph_ppm_get_height(const phPPM_image ppm)
00528 {
00529     return ppm->h;
00530 }
00531 
00532 /* ----------------------------------------------------------------------------
00533  * ------------------------------------------------------------------------- */
00534 uint8_t *ph_ppm_get_data(const phPPM_image ppm)
00535 {
00536     return ppm->data;
00537 }
00538 
00539 #ifdef __cplusplus
00540 };
00541 #endif /* __cplusplus */
00542     




Copyright (C) 2002 - 2007 Philip D.S. Thoren ( pthoren@users.sourceforge.net )
University Of Massachusetts at Lowell
Robotics Lab
SourceForge.net Logo

Generated on Sat Jun 16 02:44:02 2007 for phission by  doxygen 1.4.4