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 |