pgm.c
Go to the documentation of this file.
00001 
00006 /*
00007 Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson.
00008 Copyright (C) 2013 Andrea Vedaldi.
00009 All rights reserved.
00010 
00011 This file is part of the VLFeat library and is made available under
00012 the terms of the BSD license (see the COPYING file).
00013 */
00014 
00039 #include "pgm.h"
00040 
00041 #include <stdio.h>
00042 #include <stdlib.h>
00043 #include <string.h>
00044 
00051 static int
00052 remove_line(FILE* f)
00053 {
00054   int count = 0 ;
00055   int c ;
00056 
00057   while (1) {
00058     c = fgetc(f) ;
00059     ++ count ;
00060 
00061     switch(c) {
00062     case '\n' :
00063       goto quit_remove_line ;
00064 
00065     case EOF :
00066       -- count ;
00067       goto quit_remove_line ;
00068     }
00069   }
00070  quit_remove_line :
00071   return count ;
00072 }
00073 
00080 static int
00081 remove_blanks(FILE* f)
00082 {
00083   int count = 0 ;
00084   int c ;
00085 
00086   while (1) {
00087     c = fgetc(f) ;
00088 
00089     switch(c) {
00090 
00091     case '\t' : case '\n' :
00092     case '\r' : case ' '  :
00093       ++ count ;
00094       break ;
00095 
00096     case '#' :
00097       count += 1 + remove_line(f) ;
00098       break ;
00099 
00100     case EOF :
00101       goto quit_remove_blanks ;
00102 
00103     default:
00104       ungetc(c, f) ;
00105       goto quit_remove_blanks ;
00106     }
00107   }
00108  quit_remove_blanks:
00109   return count ;
00110 }
00111 
00124 VL_EXPORT vl_size
00125 vl_pgm_get_npixels (VlPgmImage const *im)
00126 {
00127   return im->width * im->height ;
00128 }
00129 
00139 VL_EXPORT vl_size
00140 vl_pgm_get_bpp (VlPgmImage const *im)
00141 {
00142   return (im->max_value >= 256) + 1 ;
00143 }
00144 
00160 VL_EXPORT int
00161 vl_pgm_extract_head (FILE* f, VlPgmImage *im)
00162 {
00163   char magic [2] ;
00164   int c ;
00165   int is_raw ;
00166   int width ;
00167   int height ;
00168   int max_value ;
00169   size_t sz ;
00170   vl_bool good ;
00171 
00172   /* -----------------------------------------------------------------
00173    *                                                check magic number
00174    * -------------------------------------------------------------- */
00175   sz = fread(magic, 1, 2, f) ;
00176 
00177   if (sz < 2) {
00178     return vl_set_last_error(VL_ERR_PGM_INV_HEAD, "Invalid PGM header") ;
00179   }
00180 
00181   good = magic [0] == 'P' ;
00182 
00183   switch (magic [1]) {
00184   case '2' : /* ASCII format */
00185     is_raw = 0 ;
00186     break ;
00187 
00188   case '5' : /* RAW format */
00189     is_raw = 1 ;
00190     break ;
00191 
00192   default :
00193     good = 0 ;
00194     break ;
00195   }
00196 
00197   if( ! good ) {
00198     return vl_set_last_error(VL_ERR_PGM_INV_HEAD, "Invalid PGM header") ;
00199   }
00200 
00201   /* -----------------------------------------------------------------
00202    *                                    parse width, height, max_value
00203    * -------------------------------------------------------------- */
00204   good = 1 ;
00205 
00206   c = remove_blanks(f) ;
00207   good &= c > 0 ;
00208 
00209   c = fscanf(f, "%d", &width) ;
00210   good &= c == 1 ;
00211 
00212   c = remove_blanks(f) ;
00213   good &= c > 0 ;
00214 
00215   c = fscanf(f, "%d", &height) ;
00216   good &= c == 1 ;
00217 
00218   c = remove_blanks(f) ;
00219   good &= c > 0 ;
00220 
00221   c = fscanf(f, "%d", &max_value) ;
00222   good &= c == 1 ;
00223 
00224   /* must end with a single blank */
00225   c = fgetc(f) ;
00226   good &=
00227     c == '\n' ||
00228     c == '\t' ||
00229     c == ' '  ||
00230     c == '\r' ;
00231 
00232   if(! good) {
00233     return vl_set_last_error(VL_ERR_PGM_INV_META, "Invalid PGM meta information");
00234   }
00235 
00236   if(! max_value >= 65536) {
00237     return vl_set_last_error(VL_ERR_PGM_INV_META, "Invalid PGM meta information");
00238   }
00239 
00240   /* exit */
00241   im-> width     = width ;
00242   im-> height    = height ;
00243   im-> max_value = max_value ;
00244   im-> is_raw    = is_raw ;
00245   return 0 ;
00246 }
00247 
00261 VL_EXPORT
00262 int
00263 vl_pgm_extract_data (FILE* f, VlPgmImage const *im, void *data)
00264 {
00265   vl_size bpp = vl_pgm_get_bpp(im) ;
00266   vl_size data_size = vl_pgm_get_npixels(im) ;
00267   vl_bool good = 1 ;
00268   size_t c ;
00269 
00270   /* -----------------------------------------------------------------
00271    *                                                         read data
00272    * -------------------------------------------------------------- */
00273 
00274   /*
00275      In RAW mode we read directly an array of bytes or shorts.  In
00276      the latter case, however, we must take care of the
00277      endianess. PGM files are sorted in big-endian format. If our
00278      architecture is little endian, we must do a conversion.
00279   */
00280   if (im->is_raw) {
00281 
00282     c = fread( data,
00283                bpp,
00284                data_size,
00285                f ) ;
00286     good = (c == data_size) ;
00287 
00288     /* adjust endianess */
00289 #if defined(VL_ARCH_LITTLE_ENDIAN)
00290     if (bpp == 2) {
00291       vl_uindex i ;
00292       vl_uint8 *pt = (vl_uint8*) data ;
00293       for(i = 0 ; i < 2 * data_size ; i += 2) {
00294         vl_uint8 tmp = pt [i] ;
00295         pt [i]   = pt [i+1] ;
00296         pt [i+1] = tmp ;
00297       }
00298     }
00299 #endif
00300   }
00301   /*
00302      In ASCII mode we read a sequence of decimal numbers separated
00303      by whitespaces.
00304   */
00305   else {
00306     vl_uindex i ;
00307     int unsigned v ;
00308     for(good = 1, i = 0 ;
00309         i < data_size && good ;
00310         ++i) {
00311       c = fscanf(f, " %ud", &v) ;
00312       if (bpp == 1) {
00313         * ((vl_uint8* )  data + i) = (vl_uint8)  v ;
00314       } else {
00315         * ((vl_uint16*)  data + i) = (vl_uint16) v ;
00316       }
00317       good &= c == 1 ;
00318     }
00319   }
00320 
00321   if(! good ) {
00322     return vl_set_last_error(VL_ERR_PGM_INV_DATA, "Invalid PGM data") ;
00323   }
00324   return 0 ;
00325 }
00326 
00335 VL_EXPORT
00336 int
00337 vl_pgm_insert(FILE* f, VlPgmImage const *im, void const *data)
00338 {
00339   vl_size bpp = vl_pgm_get_bpp (im) ;
00340   vl_size data_size = vl_pgm_get_npixels (im) ;
00341   size_t c ;
00342 
00343   /* write preamble */
00344   fprintf(f,
00345           "P5\n%d\n%d\n%d\n",
00346           (signed)im->width,
00347           (signed)im->height,
00348           (signed)im->max_value) ;
00349 
00350   /* take care of endianness */
00351 #if defined(VL_ARCH_LITTLE_ENDIAN)
00352   if (bpp == 2) {
00353     vl_uindex i ;
00354     vl_uint8* temp = vl_malloc (2 * data_size) ;
00355     memcpy(temp, data, 2 * data_size) ;
00356     for(i = 0 ; i < 2 * data_size ; i += 2) {
00357       vl_uint8 tmp = temp [i] ;
00358       temp [i]   = temp [i+1] ;
00359       temp [i+1] = tmp ;
00360     }
00361     c = fwrite(temp, 2, data_size, f) ;
00362     vl_free (temp) ;
00363   }
00364   else {
00365 #endif
00366     c = fwrite(data, bpp, data_size, f) ;
00367 #if defined(VL_ARCH_LITTLE_ENDIAN)
00368   }
00369 #endif
00370 
00371   if(c != data_size) {
00372     return vl_set_last_error(VL_ERR_PGM_IO, "Error writing PGM data") ;
00373   }
00374   return 0 ;
00375 }
00376 
00393 VL_EXPORT
00394 int vl_pgm_read_new (char const *name, VlPgmImage *im, vl_uint8** data)
00395 {
00396   int err = 0 ;
00397   FILE *f = fopen (name, "rb") ;
00398 
00399   if (! f) {
00400     return vl_set_last_error(VL_ERR_PGM_IO, "Error opening PGM file `%s' for reading", name) ;
00401   }
00402 
00403   err = vl_pgm_extract_head(f, im) ;
00404   if (err) {
00405     fclose (f) ;
00406     return err ;
00407   }
00408 
00409   if (vl_pgm_get_bpp(im) > 1) {
00410     return vl_set_last_error(VL_ERR_BAD_ARG, "PGM with BPP > 1 not supported") ;
00411   }
00412 
00413   *data = vl_malloc (vl_pgm_get_npixels(im) * sizeof(vl_uint8)) ;
00414   err = vl_pgm_extract_data(f, im, *data) ;
00415 
00416   if (err) {
00417     vl_free (data) ;
00418     fclose (f) ;
00419   }
00420 
00421   fclose (f) ;
00422   return err ;
00423 }
00424 
00442 VL_EXPORT
00443 int vl_pgm_read_new_f (char const *name,  VlPgmImage *im, float** data)
00444 {
00445   int err = 0 ;
00446   size_t npixels ;
00447   vl_uint8 *idata ;
00448 
00449   err = vl_pgm_read_new (name, im, &idata) ;
00450   if (err) {
00451     return err ;
00452   }
00453 
00454   npixels = vl_pgm_get_npixels(im) ;
00455   *data = vl_malloc (sizeof(float) * npixels) ;
00456   {
00457     size_t k ;
00458     float scale = 1.0f / (float)im->max_value ;
00459     for (k = 0 ; k < npixels ; ++ k) (*data)[k] = scale * idata[k] ;
00460   }
00461 
00462   vl_free (idata) ;
00463   return 0 ;
00464 }
00465 
00479 VL_EXPORT
00480 int vl_pgm_write (char const *name, vl_uint8 const* data, int width, int height)
00481 {
00482   int err = 0 ;
00483   VlPgmImage pgm ;
00484   FILE *f = fopen (name, "wb") ;
00485 
00486   if (! f) {
00487     return vl_set_last_error(VL_ERR_PGM_IO,
00488              "Error opening PGM file '%s' for writing", name) ;
00489   }
00490 
00491   pgm.width = width ;
00492   pgm.height = height ;
00493   pgm.is_raw = 1 ;
00494   pgm.max_value = 255 ;
00495 
00496   err = vl_pgm_insert (f, &pgm, data) ;
00497   fclose (f) ;
00498 
00499   return err ;
00500 }
00501 
00516 VL_EXPORT
00517 int vl_pgm_write_f (char const *name, float const* data, int width, int height)
00518 {
00519   int err = 0 ;
00520   int k ;
00521   float min = + VL_INFINITY_F ;
00522   float max = - VL_INFINITY_F ;
00523   float scale ;
00524 
00525   vl_uint8 * buffer = vl_malloc (sizeof(float) * width * height) ;
00526 
00527   for (k = 0 ; k < width * height ; ++k) {
00528     min = VL_MIN(min, data [k]) ;
00529     max = VL_MAX(max, data [k]) ;
00530   }
00531 
00532   scale = 255 / (max - min + VL_EPSILON_F) ;
00533 
00534   for (k = 0 ; k < width * height ; ++k) {
00535     buffer [k] = (vl_uint8) ((data [k] - min) * scale) ;
00536   }
00537 
00538   err = vl_pgm_write (name, buffer, width, height) ;
00539 
00540   vl_free (buffer) ;
00541   return err ;
00542 }


libvlfeat
Author(s): Andrea Vedaldi
autogenerated on Thu Jun 6 2019 20:25:51