Panda3D
 All Classes Functions Variables Enumerations
pnmFileTypePNM.cxx
00001 // Filename: pnmFileTypePNM.cxx
00002 // Created by:  drose (04Apr98)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "pnmFileTypePNM.h"
00016 
00017 #ifdef HAVE_PNM
00018 
00019 #include "config_pnmimagetypes.h"
00020 
00021 #include "pnmFileTypeRegistry.h"
00022 #include "bamReader.h"
00023 
00024 static const char * const extensions_PNM[] = {
00025   "pbm", "pgm", "ppm", "pnm"
00026 };
00027 static const int num_extensions_PNM = sizeof(extensions_PNM) / sizeof(const char *);
00028 
00029 TypeHandle PNMFileTypePNM::_type_handle;
00030 
00031 // Some macros lifted from the original Netpbm sources.
00032 
00033 #define PBM_MAGIC1 'P'
00034 #define PBM_MAGIC2 '1'
00035 #define RPBM_MAGIC2 '4'
00036 #define PBM_FORMAT (PBM_MAGIC1 * 256 + PBM_MAGIC2)
00037 #define RPBM_FORMAT (PBM_MAGIC1 * 256 + RPBM_MAGIC2)
00038 #define PBM_TYPE PBM_FORMAT
00039 
00040 #define PBM_FORMAT_TYPE(f)                                      \
00041   ((f) == PBM_FORMAT || (f) == RPBM_FORMAT ? PBM_TYPE : -1)
00042 
00043 #define PGM_OVERALLMAXVAL 65535
00044 
00045 #define PGM_MAGIC1 'P'
00046 #define PGM_MAGIC2 '2'
00047 #define RPGM_MAGIC2 '5'
00048 #define PGM_FORMAT (PGM_MAGIC1 * 256 + PGM_MAGIC2)
00049 #define RPGM_FORMAT (PGM_MAGIC1 * 256 + RPGM_MAGIC2)
00050 #define PGM_TYPE PGM_FORMAT
00051 
00052 #define PGM_FORMAT_TYPE(f) ((f) == PGM_FORMAT || (f) == RPGM_FORMAT ? PGM_TYPE : PBM_FORMAT_TYPE(f))
00053 
00054 #define PPM_OVERALLMAXVAL PGM_OVERALLMAXVAL
00055 #define PPM_MAXMAXVAL PGM_MAXMAXVAL
00056 
00057 #define PPM_MAGIC1 'P'
00058 #define PPM_MAGIC2 '3'
00059 #define RPPM_MAGIC2 '6'
00060 #define PPM_FORMAT (PPM_MAGIC1 * 256 + PPM_MAGIC2)
00061 #define RPPM_FORMAT (PPM_MAGIC1 * 256 + RPPM_MAGIC2)
00062 #define PPM_TYPE PPM_FORMAT
00063 
00064 #define PPM_FORMAT_TYPE(f)                                              \
00065   ((f) == PPM_FORMAT || (f) == RPPM_FORMAT ? PPM_TYPE : PGM_FORMAT_TYPE(f))
00066 
00067 #define PNM_OVERALLMAXVAL PPM_OVERALLMAXVAL
00068 #define PNM_GET1(x) PPM_GETB(x)
00069 
00070 #define PNM_FORMAT_TYPE(f) PPM_FORMAT_TYPE(f)
00071 
00072 typedef unsigned char bit;
00073 #define PBM_WHITE 0
00074 #define PBM_BLACK 1
00075 
00076 #define pbm_allocarray(cols, rows)                      \
00077   ((bit**) pm_allocarray(cols, rows, sizeof(bit)))
00078 #define pbm_allocrow(cols) ((bit*) pm_allocrow(cols, sizeof(bit)))
00079 #define pbm_freearray(bits, rows) pm_freearray((char**) bits, rows)
00080 #define pbm_freerow(bitrow) pm_freerow((char*) bitrow)
00081 #define pbm_packed_bytes(cols) (((cols)+7)/8)
00082 #define pbm_allocrow_packed(cols)                               \
00083   ((unsigned char *) pm_allocrow(pbm_packed_bytes(cols),        \
00084                                  sizeof(unsigned char)))
00085 #define pbm_freerow_packed(packed_bits)         \
00086   pm_freerow((char *) packed_bits)
00087 #define pbm_allocarray_packed(cols, rows) ((unsigned char **)           \
00088                                            pm_allocarray(pbm_packed_bytes(cols), rows, sizeof(unsigned char)))
00089 #define pbm_freearray_packed(packed_bits, rows) \
00090   pm_freearray((char **) packed_bits, rows)
00091 
00092 #define pgm_allocarray( cols, rows ) ((gray**) pm_allocarray( cols, rows, sizeof(gray) ))
00093 #define pgm_allocrow( cols ) ((gray*) pm_allocrow( cols, sizeof(gray) ))
00094 #define pgm_freearray( grays, rows ) pm_freearray( (char**) grays, rows )
00095 #define pgm_freerow( grayrow ) pm_freerow( (char*) grayrow )
00096 
00097 #define ppm_allocarray( cols, rows ) ((pixel**) pm_allocarray( cols, rows, sizeof(pixel) ))
00098 #define ppm_allocrow( cols ) ((pixel*) pm_allocrow( cols, sizeof(pixel) ))
00099 #define ppm_freearray( pixels, rows ) pm_freearray( (char**) pixels, rows )
00100 #define ppm_freerow( pixelrow ) pm_freerow( (char*) pixelrow )
00101 
00102 static const bool pm_plain_output = false;
00103 
00104 // Some functions lifted from Netpbm and adapted to use C++ iostreams.
00105 
00106 
00107 char**
00108 pm_allocarray(int const cols, int const rows, int const size )  {
00109   /*----------------------------------------------------------------------------
00110     Allocate an array of 'rows' rows of 'cols' columns each, with each
00111     element 'size' bytes.
00112 
00113     We use a special format where we tack on an extra element to the row
00114     index to indicate the format of the array.
00115 
00116     We have two ways of allocating the space: fragmented and
00117     unfragmented.  In both, the row index (plus the extra element) is
00118     in one block of memory.  In the fragmented format, each row is
00119     also in an independent memory block, and the extra row pointer is
00120     NULL.  In the unfragmented format, all the rows are in a single
00121     block of memory called the row heap and the extra row pointer is
00122     the address of that block.
00123 
00124     We use unfragmented format if possible, but if the allocation of the
00125     row heap fails, we fall back to fragmented.
00126     -----------------------------------------------------------------------------*/
00127   char** rowIndex;
00128   char * rowheap;
00129 
00130   rowIndex = (char **)PANDA_MALLOC_ARRAY((rows + 1) * sizeof(char *));
00131   if ( rowIndex == NULL )
00132     pm_error("out of memory allocating row index (%u rows) for an array",
00133              rows);
00134   rowheap = (char *)PANDA_MALLOC_ARRAY( rows * cols * size );
00135   if ( rowheap == NULL ) {
00136     /* We couldn't get the whole heap in one block, so try fragmented
00137        format.
00138     */
00139     unsigned int row;
00140         
00141     rowIndex[rows] = NULL;   /* Declare it fragmented format */
00142 
00143     for (row = 0; row < rows; ++row) {
00144       rowIndex[row] = pm_allocrow(cols, size);
00145       if (rowIndex[row] == NULL)
00146         pm_error("out of memory allocating Row %u "
00147                  "(%u columns, %u bytes per tuple) "
00148                  "of an array", row, cols, size);
00149     }
00150   } else {
00151     /* It's unfragmented format */
00152     unsigned int row;
00153     rowIndex[rows] = rowheap;  /* Declare it unfragmented format */
00154 
00155     for (row = 0; row < rows; ++row)
00156       rowIndex[row] = &(rowheap[row * cols * size]);
00157   }
00158   return rowIndex;
00159 }
00160 
00161 void
00162 pm_freearray(char ** const rowIndex, 
00163              int     const rows) {
00164 
00165   void * const rowheap = rowIndex[rows];
00166 
00167   if (rowheap != NULL)
00168     PANDA_FREE_ARRAY(rowheap);
00169   else {
00170     unsigned int row;
00171     for (row = 0; row < rows; ++row)
00172       pm_freerow(rowIndex[row]);
00173   }
00174   PANDA_FREE_ARRAY(rowIndex);
00175 }
00176 
00177 static unsigned int
00178 pm_getuint(istream * const ifP) {
00179   /*----------------------------------------------------------------------------
00180     Read an unsigned integer in ASCII decimal from the file stream
00181     represented by 'ifP' and return its value.
00182 
00183     If there is nothing at the current position in the file stream that
00184     can be interpreted as an unsigned integer, issue an error message
00185     to stderr and abort the program.
00186 
00187     If the number at the current position in the file stream is too
00188     great to be represented by an 'int' (Yes, I said 'int', not
00189     'unsigned int'), issue an error message to stderr and abort the
00190     program.
00191     -----------------------------------------------------------------------------*/
00192   char ch;
00193   unsigned int i;
00194     
00195   // skip whitespace
00196   do {
00197     ch = ifP->get();
00198 
00199     if (ch == '#') {
00200       // Skip a comment
00201       do {
00202         ch = ifP->get();
00203       } while (ch != EOF && ch != '\n');
00204     }
00205   } while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r');
00206       
00207   if (ch < '0' || ch > '9')
00208     pm_error("junk in file where an unsigned integer should be");
00209 
00210   i = 0;
00211   do {
00212     unsigned int const digitVal = ch - '0';
00213 
00214     if (i > INT_MAX/10 - digitVal)
00215       pm_error("ASCII decimal integer in file is "
00216                "too large to be processed.  ");
00217     i = i * 10 + digitVal;
00218     ch = ifP->get();
00219   } while (ch >= '0' && ch <= '9');
00220 
00221   return i;
00222 }
00223 
00224 static void
00225 ppm_readppminitrest(istream *   const file, 
00226                     int *    const colsP, 
00227                     int *    const rowsP, 
00228                     pixval * const maxvalP) {
00229   unsigned int maxval;
00230 
00231   /* Read size. */
00232   *colsP = (int)pm_getuint(file);
00233   *rowsP = (int)pm_getuint(file);
00234 
00235   /* Read maxval. */
00236   maxval = pm_getuint(file);
00237   if (maxval > PPM_OVERALLMAXVAL)
00238     pm_error("maxval of input image (%u) is too large.  "
00239              "The maximum allowed by the PPM is %u.",
00240              maxval, PPM_OVERALLMAXVAL); 
00241   if (maxval == 0)
00242     pm_error("maxval of input image is zero.");
00243 
00244   *maxvalP = maxval;
00245 }
00246 
00247 static void
00248 pgm_readpgminitrest(istream * const file, 
00249                     int *  const colsP, 
00250                     int *  const rowsP, 
00251                     gray * const maxvalP) {
00252 
00253   gray maxval;
00254     
00255   /* Read size. */
00256   *colsP = (int)pm_getuint(file);
00257   *rowsP = (int)pm_getuint(file);
00258 
00259   /* Read maxval. */
00260   maxval = pm_getuint(file);
00261   if (maxval > PGM_OVERALLMAXVAL)
00262     pm_error("maxval of input image (%u) is too large.  "
00263              "The maximum allowed by PGM is %u.", 
00264              maxval, PGM_OVERALLMAXVAL);
00265   if (maxval == 0)
00266     pm_error("maxval of input image is zero.");
00267 
00268   *maxvalP = maxval;
00269 }
00270 
00271 static void
00272 pbm_readpbminitrest(istream* file,
00273                     int* colsP,
00274                     int* rowsP) {
00275   /* Read size. */
00276   *colsP = (int)pm_getuint( file );
00277   *rowsP = (int)pm_getuint( file );
00278 
00279   /* *colsP and *rowsP really should be unsigned int, but they come
00280      from the time before unsigned ints (or at least from a person
00281      trained in that tradition), so they are int.  We could simply
00282      consider negative numbers to mean values > INT_MAX/2 and much
00283      code would just automatically work.  But some code would fail
00284      miserably.  So we consider values that won't fit in an int to
00285      be unprocessable.
00286   */
00287   if (*colsP < 0)
00288     pm_error("Number of columns in header is too large.");
00289   if (*rowsP < 0)
00290     pm_error("Number of columns in header is too large.");
00291 }
00292 
00293 static unsigned char
00294 pm_getrawbyte(istream * const file) {
00295   int iby;
00296 
00297   iby = file->get();
00298   if (iby == EOF)
00299     pm_error("EOF / read error reading a one-byte sample");
00300   return (unsigned char) iby;
00301 }
00302 
00303 static bit 
00304 getbit (istream * const file) {
00305   char ch;
00306 
00307   do {
00308     ch = file->get();
00309   } while ( ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' );
00310 
00311   if ( ch != '0' && ch != '1' )
00312     pm_error( "junk in file where bits should be" );
00313     
00314   return ( ch == '1' ) ? 1 : 0;
00315 }
00316 
00317 static void
00318 pbm_readpbmrow( istream *file, bit *bitrow, int cols, int format ) {
00319   register int col, bitshift;
00320   register bit* bP;
00321 
00322   switch ( format )
00323     {
00324     case PBM_FORMAT:
00325       for ( col = 0, bP = bitrow; col < cols; ++col, ++bP )
00326         *bP = getbit( file );
00327       break;
00328 
00329     case RPBM_FORMAT: {
00330       register unsigned char item;
00331       bitshift = -1;  item = 0;  /* item's value is meaningless here */
00332       for ( col = 0, bP = bitrow; col < cols; ++col, ++bP )
00333         {
00334           if ( bitshift == -1 )
00335             {
00336               item = pm_getrawbyte( file );
00337               bitshift = 7;
00338             }
00339           *bP = ( item >> bitshift ) & 1;
00340           --bitshift;
00341         }
00342     }
00343       break;
00344 
00345     default:
00346       pm_error( "can't happen" );
00347     }
00348 }
00349 
00350 static gray
00351 pgm_getrawsample(istream * const file, gray const maxval) {
00352 
00353   if (maxval < 256) {
00354     /* The sample is just one byte.  Read it. */
00355     return(pm_getrawbyte(file));
00356   } else {
00357     /* The sample is two bytes.  Read both. */
00358     unsigned char byte_pair[2];
00359     size_t pairs_read;
00360 
00361     file->read((char *)byte_pair, 2);
00362     pairs_read = file->gcount();
00363     if (pairs_read == 0) 
00364       pm_error("EOF /read error while reading a long sample");
00365     /* This could be a few instructions faster if exploited the internal
00366        format (i.e. endianness) of a pixval.  Then we might be able to
00367        skip the shifting and oring.
00368     */
00369     return((byte_pair[0]<<8) | byte_pair[1]);
00370   }
00371 }
00372 
00373 static void
00374 pgm_readpgmrow(istream* const file, gray* const grayrow, 
00375                int const cols, gray const maxval, int const format) {
00376 
00377   switch (format) {
00378   case PGM_FORMAT: {
00379     int col;
00380     for (col = 0; col < cols; ++col) {
00381       grayrow[col] = pm_getuint(file);
00382 #ifdef DEBUG
00383       if (grayrow[col] > maxval)
00384         pm_error( "value out of bounds (%u > %u)", 
00385                   grayrow[col], maxval );
00386 #endif /*DEBUG*/
00387     }
00388   }
00389     break;
00390         
00391   case RPGM_FORMAT: {
00392     int col;
00393     for (col = 0; col < cols; ++col) {
00394       grayrow[col] = pgm_getrawsample( file, maxval );
00395 #ifdef DEBUG
00396       if ( grayrow[col] > maxval )
00397         pm_error( "value out of bounds (%u > %u)", 
00398                   grayrow[col], maxval );
00399 #endif /*DEBUG*/
00400     }
00401   }
00402     break;
00403     
00404   case PBM_FORMAT:
00405   case RPBM_FORMAT:
00406     {
00407       bit * bitrow;
00408       int col;
00409 
00410       bitrow = pbm_allocrow(cols);
00411       pbm_readpbmrow( file, bitrow, cols, format );
00412       for (col = 0; col < cols; ++col)
00413         grayrow[col] = (bitrow[col] == PBM_WHITE ) ? maxval : 0;
00414       pbm_freerow(bitrow);
00415     }
00416     break;
00417         
00418   default:
00419     pm_error( "can't happen" );
00420   }
00421 }
00422 
00423 static void
00424 ppm_readppmrow(istream*  const fileP, 
00425                pixel* const pixelrow, 
00426                int    const cols, 
00427                pixval const maxval, 
00428                int    const format) {
00429 
00430   switch (format) {
00431   case PPM_FORMAT: {
00432     unsigned int col;
00433     for (col = 0; col < cols; ++col) {
00434       pixval const r = pm_getuint(fileP);
00435       pixval const g = pm_getuint(fileP);
00436       pixval const b = pm_getuint(fileP);
00437       PPM_ASSIGN(pixelrow[col], r, g, b);
00438     }
00439   }
00440     break;
00441 
00442   case RPPM_FORMAT: {
00443     unsigned int col;
00444     for (col = 0; col < cols; ++col) {
00445       pixval const r = pgm_getrawsample(fileP, maxval);
00446       pixval const g = pgm_getrawsample(fileP, maxval);
00447       pixval const b = pgm_getrawsample(fileP, maxval);
00448       PPM_ASSIGN(pixelrow[col], r, g, b);
00449     }
00450   }
00451     break;
00452 
00453   case PGM_FORMAT:
00454   case RPGM_FORMAT: {
00455     gray * const grayrow = pgm_allocrow(cols);
00456     unsigned int col;
00457 
00458     pgm_readpgmrow(fileP, grayrow, cols, maxval, format);
00459     for (col = 0; col < cols; ++col) {
00460       pixval const g = grayrow[col];
00461       PPM_ASSIGN(pixelrow[col], g, g, g);
00462     }
00463     pgm_freerow(grayrow);
00464   }
00465     break;
00466 
00467   case PBM_FORMAT:
00468   case RPBM_FORMAT: {
00469     bit * const bitrow = pbm_allocrow(cols);
00470     unsigned int col;
00471 
00472     pbm_readpbmrow(fileP, bitrow, cols, format);
00473     for (col = 0; col < cols; ++col) {
00474       pixval const g = (bitrow[col] == PBM_WHITE) ? maxval : 0;
00475       PPM_ASSIGN(pixelrow[col], g, g, g);
00476     }
00477     pbm_freerow(bitrow);
00478   }
00479     break;
00480 
00481   default:
00482     pm_error("Invalid format code");
00483   }
00484 }
00485 
00486 static void
00487 pnm_readpnmrow( istream* file, xel* xelrow, int cols, xelval maxval, int format ) {
00488   register int col;
00489   register xel* xP;
00490   gray* grayrow;
00491   register gray* gP;
00492   bit* bitrow;
00493   register bit* bP;
00494 
00495   switch ( PNM_FORMAT_TYPE(format) )
00496     {
00497     case PPM_TYPE:
00498       ppm_readppmrow( file, (pixel*) xelrow, cols, (pixval) maxval, format );
00499       break;
00500 
00501     case PGM_TYPE:
00502       grayrow = pgm_allocrow( cols );
00503       pgm_readpgmrow( file, grayrow, cols, (gray) maxval, format );
00504       for ( col = 0, xP = xelrow, gP = grayrow; col < cols; ++col, ++xP, ++gP )
00505         PNM_ASSIGN1( *xP, *gP );
00506       pgm_freerow( grayrow );
00507       break;
00508 
00509     case PBM_TYPE:
00510       bitrow = pbm_allocrow( cols );
00511       pbm_readpbmrow( file, bitrow, cols, format );
00512       for ( col = 0, xP = xelrow, bP = bitrow; col < cols; ++col, ++xP, ++bP )
00513         PNM_ASSIGN1( *xP, *bP == PBM_BLACK ? 0: maxval );
00514       pbm_freerow( bitrow );
00515       break;
00516 
00517     default:
00518       pm_error( "can't happen" );
00519     }
00520 }
00521 
00522 static void
00523 pbm_writepbminit(ostream * const fileP, 
00524                  int    const cols, 
00525                  int    const rows, 
00526                  int    const forceplain) {
00527 
00528   if (!forceplain && !pm_plain_output) {
00529     (*fileP) 
00530       << (char)PBM_MAGIC1
00531       << (char)RPBM_MAGIC2
00532       << '\n'
00533       << cols << ' ' << rows << '\n';
00534   } else {
00535     (*fileP) 
00536       << (char)PBM_MAGIC1
00537       << (char)PBM_MAGIC2
00538       << '\n'
00539       << cols << ' ' << rows << '\n';
00540   }
00541 }
00542 
00543 static void
00544 pgm_writepgminit(ostream * const fileP, 
00545                  int    const cols, 
00546                  int    const rows, 
00547                  gray   const maxval, 
00548                  int    const forceplain) {
00549 
00550   bool const plainFormat = forceplain || pm_plain_output;
00551 
00552   if (maxval > PGM_OVERALLMAXVAL && !plainFormat) 
00553     pm_error("too-large maxval passed to ppm_writepgminit(): %d.\n"
00554              "Maximum allowed by the PGM format is %d.",
00555              maxval, PGM_OVERALLMAXVAL);
00556 
00557   (*fileP) 
00558     << (char)PGM_MAGIC1
00559     << (char)(plainFormat || maxval >= 1<<16 ? PGM_MAGIC2 : RPGM_MAGIC2)
00560     << '\n'
00561     << cols << ' ' << rows << '\n' << maxval << '\n';
00562 }
00563 
00564 static void
00565 ppm_writeppminit(ostream*  const fileP, 
00566                  int    const cols, 
00567                  int    const rows, 
00568                  pixval const maxval, 
00569                  int    const forceplain) {
00570 
00571   bool const plainFormat = forceplain || pm_plain_output;
00572 
00573   if (maxval > PPM_OVERALLMAXVAL && !plainFormat) 
00574     pm_error("too-large maxval passed to ppm_writeppminit(): %d."
00575              "Maximum allowed by the PPM format is %d.",
00576              maxval, PPM_OVERALLMAXVAL);
00577 
00578   (*fileP) 
00579     << (char)PPM_MAGIC1
00580     << (char)(plainFormat || maxval >= 1<<16 ? PPM_MAGIC2 : RPPM_MAGIC2)
00581     << '\n'
00582     << cols << ' ' << rows << '\n' << maxval << '\n';
00583 }
00584 
00585 static void
00586 pnm_writepnminit(ostream * const fileP, 
00587                  int    const cols, 
00588                  int    const rows, 
00589                  xelval const maxval, 
00590                  int    const format, 
00591                  int    const forceplain) {
00592 
00593   bool const plainFormat = forceplain || pm_plain_output;
00594 
00595   switch (PNM_FORMAT_TYPE(format)) {
00596   case PPM_TYPE:
00597     ppm_writeppminit(fileP, cols, rows, (pixval) maxval, plainFormat);
00598     break;
00599 
00600   case PGM_TYPE:
00601     pgm_writepgminit(fileP, cols, rows, (gray) maxval, plainFormat);
00602     break;
00603 
00604   case PBM_TYPE:
00605     pbm_writepbminit(fileP, cols, rows, plainFormat);
00606     break;
00607 
00608   default:
00609     pm_error("invalid format argument received by pnm_writepnminit(): %d"
00610              "PNM_FORMAT_TYPE(format) must be %d, %d, or %d", 
00611              format, PBM_TYPE, PGM_TYPE, PPM_TYPE);
00612   }
00613 }
00614 
00615 static void
00616 packBitsGeneric(ostream *          const fileP,
00617                 const bit *     const bitrow,
00618                 unsigned char * const packedBits,
00619                 int             const cols,
00620                 int *           const nextColP) {
00621   /*----------------------------------------------------------------------------
00622     Pack the bits of bitrow[] into byts at 'packedBits'.  Going left to right,
00623     stop when there aren't enough bits left to fill a whole byte.  Return
00624     as *nextColP the number of the next column after the rightmost one we
00625     packed.
00626 
00627     Don't use any special CPU facilities to do the packing.
00628     -----------------------------------------------------------------------------*/
00629   unsigned int col;
00630 
00631 #define iszero(x) ((x) == 0 ? 0 : 1)
00632 
00633   for (col = 0; col + 7 < cols; col += 8)
00634     packedBits[col/8] = (
00635                          iszero(bitrow[col+0]) << 7 |
00636                          iszero(bitrow[col+1]) << 6 |
00637                          iszero(bitrow[col+2]) << 5 |
00638                          iszero(bitrow[col+3]) << 4 |
00639                          iszero(bitrow[col+4]) << 3 |
00640                          iszero(bitrow[col+5]) << 2 |
00641                          iszero(bitrow[col+6]) << 1 |
00642                          iszero(bitrow[col+7]) << 0
00643                          );
00644   *nextColP = col;
00645 }
00646 
00647 static void
00648 writePackedRawRow(ostream *                const fileP,
00649                   const unsigned char * const packed_bits,
00650                   int                   const cols) {
00651 
00652   int bytesWritten;
00653   fileP->write((const char *)packed_bits, pbm_packed_bytes(cols));
00654   if (fileP->fail())
00655     pm_error("I/O error writing packed row to raw PBM file.");
00656 } 
00657 
00658 static void
00659 writePbmRowRaw(ostream *      const fileP,
00660                const bit * const bitrow,
00661                int         const cols) {
00662 
00663   int nextCol;
00664 
00665   unsigned char * const packedBits = pbm_allocrow_packed(cols);
00666 
00667   packBitsGeneric(fileP, bitrow, packedBits, cols, &nextCol);
00668 
00669   /* routine for partial byte at the end of packed_bits[]
00670      Prior to addition of the above enhancement,
00671      this method was used for the entire process
00672   */                   
00673 
00674   if (cols % 8 > 0) {
00675     int col;
00676     int bitshift;
00677     unsigned char item;
00678 
00679     bitshift = 7;  /* initial value */
00680     item = 0;      /* initial value */
00681     for (col = nextCol; col < cols; ++col, --bitshift )
00682       if (bitrow[col] !=0)
00683         item |= 1 << bitshift
00684           ;
00685         
00686     packedBits[col/8] = item;
00687   }
00688     
00689   writePackedRawRow(fileP, packedBits, cols);
00690     
00691   pbm_freerow_packed(packedBits);
00692 }
00693 
00694 
00695 
00696 static void
00697 writePbmRowPlain(ostream * const fileP,
00698                  bit *  const bitrow, 
00699                  int    const cols) {
00700     
00701   int col, charcount;
00702 
00703   charcount = 0;
00704   for (col = 0; col < cols; ++col) {
00705     if (charcount >= 70) {
00706       fileP->put('\n');
00707       charcount = 0;
00708     }
00709     fileP->put(bitrow[col] ? '1' : '0');
00710     ++charcount;
00711   }
00712   fileP->put('\n');
00713 }
00714 
00715 static void
00716 pbm_writepbmrow(ostream * const fileP, 
00717                 bit *  const bitrow, 
00718                 int    const cols, 
00719                 int    const forceplain) {
00720 
00721   if (!forceplain && !pm_plain_output)
00722     writePbmRowRaw(fileP, bitrow, cols);
00723   else
00724     writePbmRowPlain(fileP, bitrow, cols);
00725 }
00726 
00727 static void
00728 pgm_writerawsample(ostream *file, const gray val, const gray maxval) {
00729 
00730   if (maxval < 256) {
00731     /* Samples fit in one byte, so write just one byte */
00732     file->put(val);
00733     if (file->fail())
00734       pm_error("Error writing single byte sample to file");
00735   } else {
00736     /* Samples are too big for one byte, so write two */
00737     unsigned char outval[2];
00738     /* We could save a few instructions if we exploited the internal
00739        format of a gray, i.e. its endianness.  Then we might be able
00740        to skip the shifting and anding.
00741     */
00742     outval[0] = val >> 8;
00743     outval[1] = val & 0xFF;
00744     file->write((const char *)outval, 2);
00745     if (file->fail())
00746       pm_error("Error writing double byte sample to file");
00747   }
00748 }
00749 
00750 static void
00751 pgm_writepgmrowraw(ostream *file, gray *grayrow, int cols, gray maxval ) {
00752   int col;
00753 
00754   for (col = 0; col < cols; ++col) {
00755 #ifdef DEBUG
00756     if (grayrow[col] > maxval)
00757       pm_error( "value out of bounds (%u > %u)", grayrow[col], maxval);
00758 #endif /*DEBUG*/
00759     pgm_writerawsample(file, grayrow[col], maxval);
00760   }
00761 }
00762 
00763 static void
00764 putus(unsigned short const n, 
00765       ostream *         const fileP) {
00766 
00767   if (n >= 10)
00768     putus(n / 10, fileP);
00769   fileP->put(n % 10 + '0');
00770 }
00771 
00772 
00773 static void
00774 pgm_writepgmrowplain(ostream * const fileP,
00775                      gray * const grayrow, 
00776                      int    const cols, 
00777                      gray   const maxval) {
00778 
00779   int col, charcount;
00780   gray* gP;
00781 
00782   charcount = 0;
00783   for (col = 0, gP = grayrow; col < cols; ++col, ++gP) {
00784     if (charcount >= 65) {
00785       fileP->put('\n');
00786       charcount = 0;
00787     } else if (charcount > 0) {
00788       fileP->put(' ');
00789       ++charcount;
00790     }
00791 #ifdef DEBUG
00792     if (*gP > maxval)
00793       pm_error("value out of bounds (%u > %u)", *gP, maxval);
00794 #endif /*DEBUG*/
00795     putus((unsigned short)*gP, fileP);
00796     charcount += 3;
00797   }
00798   if (charcount > 0)
00799     fileP->put('\n');
00800 }
00801 
00802 static void
00803 pgm_writepgmrow(ostream* const fileP, 
00804                 gray* const grayrow, 
00805                 int   const cols, 
00806                 gray  const maxval, 
00807                 int   const forceplain) {
00808 
00809   if (forceplain || pm_plain_output || maxval >= 1<<16)
00810     pgm_writepgmrowplain(fileP, grayrow, cols, maxval);
00811   else
00812     pgm_writepgmrowraw(fileP, grayrow, cols, maxval);
00813 }
00814 
00815 static void
00816 ppm_writeppmrowraw(ostream *file, pixel *pixelrow, int cols, pixval maxval ) {
00817   register int col;
00818   register pixval val;
00819 
00820   for ( col = 0; col < cols; ++col )
00821     {
00822       val = PPM_GETR( pixelrow[col] );
00823 #ifdef DEBUG
00824       if ( val > maxval )
00825         pm_error( "r value out of bounds (%u > %u)", val, maxval );
00826 #endif /*DEBUG*/
00827       pgm_writerawsample( file, val, maxval );
00828       val = PPM_GETG( pixelrow[col] );
00829 #ifdef DEBUG
00830       if ( val > maxval )
00831         pm_error( "g value out of bounds (%u > %u)", val, maxval );
00832 #endif /*DEBUG*/
00833       pgm_writerawsample( file, val, maxval );
00834       val = PPM_GETB( pixelrow[col] );
00835 #ifdef DEBUG
00836       if ( val > maxval )
00837         pm_error( "b value out of bounds (%u > %u)", val, maxval );
00838 #endif /*DEBUG*/
00839       pgm_writerawsample( file, val, maxval );
00840     }
00841 }
00842 
00843 static void
00844 ppm_writeppmrowplain(ostream *file, pixel *pixelrow, int cols, pixval maxval ) {
00845   register int col, charcount;
00846   register pixel* pP;
00847   register pixval val;
00848 
00849   charcount = 0;
00850   for ( col = 0, pP = pixelrow; col < cols; ++col, ++pP )
00851     {
00852       if ( charcount >= 65 )
00853         {
00854           (void) file->put( '\n' );
00855           charcount = 0;
00856         }
00857       else if ( charcount > 0 )
00858         {
00859           (void) file->put( ' ' );
00860           (void) file->put( ' ' );
00861           charcount += 2;
00862         }
00863       val = PPM_GETR( *pP );
00864 #ifdef DEBUG
00865       if ( val > maxval )
00866         pm_error( "r value out of bounds (%u > %u)", val, maxval );
00867 #endif /*DEBUG*/
00868       putus( val, file );
00869       (void) file->put( ' ' );
00870       val = PPM_GETG( *pP );
00871 #ifdef DEBUG
00872       if ( val > maxval )
00873         pm_error( "g value out of bounds (%u > %u)", val, maxval );
00874 #endif /*DEBUG*/
00875       putus( val, file );
00876       (void) file->put( ' ' );
00877       val = PPM_GETB( *pP );
00878 #ifdef DEBUG
00879       if ( val > maxval )
00880         pm_error( "b value out of bounds (%u > %u)", val, maxval );
00881 #endif /*DEBUG*/
00882       putus( val, file );
00883       charcount += 11;
00884     }
00885   if ( charcount > 0 )
00886     (void) file->put( '\n' );
00887 }
00888 
00889 static void
00890 ppm_writeppmrow(ostream *  const fileP, 
00891                 pixel * const pixelrow, 
00892                 int     const cols, 
00893                 pixval  const maxval, 
00894                 int     const forceplain) {
00895 
00896   if (forceplain || pm_plain_output || maxval >= 1<<16) 
00897     ppm_writeppmrowplain(fileP, pixelrow, cols, maxval);
00898   else 
00899     ppm_writeppmrowraw(fileP, pixelrow, cols, maxval);
00900 }
00901 
00902 static void
00903 pnm_writepnmrow(ostream * const fileP, 
00904                 xel *  const xelrow, 
00905                 int    const cols, 
00906                 xelval const maxval, 
00907                 int    const format, 
00908                 int    const forceplain) {
00909 
00910   bool const plainFormat = forceplain || pm_plain_output;
00911     
00912   switch (PNM_FORMAT_TYPE(format)) {
00913   case PPM_TYPE:
00914     ppm_writeppmrow(fileP, (pixel*) xelrow, cols, (pixval) maxval, 
00915                     plainFormat);
00916     break;
00917 
00918   case PGM_TYPE: {
00919     gray* grayrow;
00920     unsigned int col;
00921 
00922     grayrow = pgm_allocrow(cols);
00923 
00924     for (col = 0; col < cols; ++col)
00925       grayrow[col] = PNM_GET1(xelrow[col]);
00926 
00927     pgm_writepgmrow(fileP, grayrow, cols, (gray) maxval, plainFormat);
00928 
00929     pgm_freerow( grayrow );
00930   }
00931     break;
00932 
00933   case PBM_TYPE: {
00934     bit* bitrow;
00935     unsigned int col;
00936 
00937     bitrow = pbm_allocrow(cols);
00938 
00939     for (col = 0; col < cols; ++col)
00940       bitrow[col] = PNM_GET1(xelrow[col]) == 0 ? PBM_BLACK : PBM_WHITE;
00941 
00942     pbm_writepbmrow(fileP, bitrow, cols, plainFormat);
00943 
00944     pbm_freerow(bitrow);
00945   }    
00946     break;
00947     
00948   default:
00949     pm_error("invalid format argument received by pnm_writepnmrow(): %d"
00950              "PNM_FORMAT_TYPE(format) must be %d, %d, or %d", 
00951              format, PBM_TYPE, PGM_TYPE, PPM_TYPE);
00952   }
00953 }
00954 
00955 ////////////////////////////////////////////////////////////////////
00956 //     Function: PNMFileTypePNM::Constructor
00957 //       Access: Public
00958 //  Description:
00959 ////////////////////////////////////////////////////////////////////
00960 PNMFileTypePNM::
00961 PNMFileTypePNM() {
00962 }
00963 
00964 ////////////////////////////////////////////////////////////////////
00965 //     Function: PNMFileTypePNM::get_name
00966 //       Access: Public, Virtual
00967 //  Description: Returns a few words describing the file type.
00968 ////////////////////////////////////////////////////////////////////
00969 string PNMFileTypePNM::
00970 get_name() const {
00971   return "NetPBM-style PBM/PGM/PPM/PNM";
00972 }
00973 
00974 ////////////////////////////////////////////////////////////////////
00975 //     Function: PNMFileTypePNM::get_num_extensions
00976 //       Access: Public, Virtual
00977 //  Description: Returns the number of different possible filename
00978 //               extensions_PNM associated with this particular file type.
00979 ////////////////////////////////////////////////////////////////////
00980 int PNMFileTypePNM::
00981 get_num_extensions() const {
00982   return num_extensions_PNM;
00983 }
00984 
00985 ////////////////////////////////////////////////////////////////////
00986 //     Function: PNMFileTypePNM::get_extension
00987 //       Access: Public, Virtual
00988 //  Description: Returns the nth possible filename extension
00989 //               associated with this particular file type, without a
00990 //               leading dot.
00991 ////////////////////////////////////////////////////////////////////
00992 string PNMFileTypePNM::
00993 get_extension(int n) const {
00994   nassertr(n >= 0 && n < num_extensions_PNM, string());
00995   return extensions_PNM[n];
00996 }
00997 
00998 ////////////////////////////////////////////////////////////////////
00999 //     Function: PNMFileTypePNM::get_suggested_extension
01000 //       Access: Public, Virtual
01001 //  Description: Returns a suitable filename extension (without a
01002 //               leading dot) to suggest for files of this type, or
01003 //               empty string if no suggestions are available.
01004 ////////////////////////////////////////////////////////////////////
01005 string PNMFileTypePNM::
01006 get_suggested_extension() const {
01007   return "ppm";
01008 }
01009 
01010 ////////////////////////////////////////////////////////////////////
01011 //     Function: PNMFileTypePNM::has_magic_number
01012 //       Access: Public, Virtual
01013 //  Description: Returns true if this particular file type uses a
01014 //               magic number to identify it, false otherwise.
01015 ////////////////////////////////////////////////////////////////////
01016 bool PNMFileTypePNM::
01017 has_magic_number() const {
01018   return true;
01019 }
01020 
01021 ////////////////////////////////////////////////////////////////////
01022 //     Function: PNMFileTypePNM::matches_magic_number
01023 //       Access: Public, Virtual
01024 //  Description: Returns true if the indicated "magic number" byte
01025 //               stream (the initial few bytes read from the file)
01026 //               matches this particular file type, false otherwise.
01027 ////////////////////////////////////////////////////////////////////
01028 bool PNMFileTypePNM::
01029 matches_magic_number(const string &magic_number) const {
01030   return (magic_number.size() >= 2) &&
01031     magic_number[0] == 'P' &&
01032     (magic_number[1] >= '1' && magic_number[1] <= '6');
01033 }
01034 
01035 ////////////////////////////////////////////////////////////////////
01036 //     Function: PNMFileTypePNM::make_reader
01037 //       Access: Public, Virtual
01038 //  Description: Allocates and returns a new PNMReader suitable for
01039 //               reading from this file type, if possible.  If reading
01040 //               from this file type is not supported, returns NULL.
01041 ////////////////////////////////////////////////////////////////////
01042 PNMReader *PNMFileTypePNM::
01043 make_reader(istream *file, bool owns_file, const string &magic_number) {
01044   init_pnm();
01045   return new Reader(this, file, owns_file, magic_number);
01046 }
01047 
01048 ////////////////////////////////////////////////////////////////////
01049 //     Function: PNMFileTypePNM::make_writer
01050 //       Access: Public, Virtual
01051 //  Description: Allocates and returns a new PNMWriter suitable for
01052 //               reading from this file type, if possible.  If writing
01053 //               files of this type is not supported, returns NULL.
01054 ////////////////////////////////////////////////////////////////////
01055 PNMWriter *PNMFileTypePNM::
01056 make_writer(ostream *file, bool owns_file) {
01057   init_pnm();
01058   return new Writer(this, file, owns_file);
01059 }
01060 
01061 
01062 ////////////////////////////////////////////////////////////////////
01063 //     Function: PNMFileTypePNM::Reader::Constructor
01064 //       Access: Public
01065 //  Description:
01066 ////////////////////////////////////////////////////////////////////
01067 PNMFileTypePNM::Reader::
01068 Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number) :
01069   PNMReader(type, file, owns_file)
01070 {
01071   if (!read_magic_number(_file, magic_number, 2)) {
01072     // No magic number.  No image.
01073     if (pnmimage_pnm_cat.is_debug()) {
01074       pnmimage_pnm_cat.debug()
01075         << "PNM file appears to be empty.\n";
01076     }
01077     _is_valid = false;
01078     return;
01079   }
01080 
01081   _ftype =
01082     ((unsigned char)magic_number[0] << 8) |
01083     (unsigned char)magic_number[1];
01084 
01085   switch ( PNM_FORMAT_TYPE(_ftype) ) {
01086   case PPM_TYPE:
01087     ppm_readppminitrest( file, &_x_size, &_y_size, &_maxval );
01088     _num_channels = 3;
01089     break;
01090 
01091   case PGM_TYPE:
01092     pgm_readpgminitrest( file, &_x_size, &_y_size, &_maxval );
01093     _num_channels = 1;
01094     break;
01095 
01096   case PBM_TYPE:
01097     pbm_readpbminitrest( file, &_x_size, &_y_size );
01098     _num_channels = 1;
01099     _maxval = 1;
01100     break;
01101 
01102   default:
01103     _is_valid = false;
01104   }
01105 
01106   if (pnmimage_pnm_cat.is_debug()) {
01107     if (is_valid()) {
01108       pnmimage_pnm_cat.debug()
01109         << "Reading ";
01110       switch (PNM_FORMAT_TYPE(_ftype)) {
01111       case PPM_TYPE:
01112         pnmimage_pnm_cat.debug(false) << "PPM";
01113         break;
01114       case PGM_TYPE:
01115         pnmimage_pnm_cat.debug(false) << "PGM";
01116         break;
01117       case PBM_TYPE:
01118         pnmimage_pnm_cat.debug(false) << "PBM";
01119         break;
01120       }
01121       pnmimage_pnm_cat.debug(false)
01122         << " " << *this << "\n";
01123     } else {
01124       pnmimage_pnm_cat.debug()
01125         << "File is not a valid PNM image.\n";
01126     }
01127   }
01128 }
01129 
01130 ////////////////////////////////////////////////////////////////////
01131 //     Function: PNMFileTypePNM::Reader::supports_read_row
01132 //       Access: Public, Virtual
01133 //  Description: Returns true if this particular PNMReader supports a
01134 //               streaming interface to reading the data: that is, it
01135 //               is capable of returning the data one row at a time,
01136 //               via repeated calls to read_row().  Returns false if
01137 //               the only way to read from this file is all at once,
01138 //               via read_data().
01139 ////////////////////////////////////////////////////////////////////
01140 bool PNMFileTypePNM::Reader::
01141 supports_read_row() const {
01142   return true;
01143 }
01144 
01145 ////////////////////////////////////////////////////////////////////
01146 //     Function: PNMFileTypePNM::Reader::read_row
01147 //       Access: Public, Virtual
01148 //  Description: If supports_read_row(), above, returns true, this
01149 //               function may be called repeatedly to read the image,
01150 //               one horizontal row at a time, beginning from the top.
01151 //               Returns true if the row is successfully read, false
01152 //               if there is an error or end of file.
01153 //
01154 //               The x_size and y_size parameters are the value of
01155 //               _x_size and _y_size as originally filled in by the
01156 //               constructor; it is the actual number of pixels in the
01157 //               image.  (The _x_size and _y_size members may have
01158 //               been automatically modified by the time this method
01159 //               is called if we are scaling on load, so should not be
01160 //               used.)
01161 ////////////////////////////////////////////////////////////////////
01162 bool PNMFileTypePNM::Reader::
01163 read_row(xel *array, xelval *, int x_size, int y_size) {
01164   if (!is_valid()) {
01165     return false;
01166   }
01167   pnm_readpnmrow(_file, array, x_size, _maxval, _ftype);
01168   return true;
01169 }
01170 
01171 
01172 ////////////////////////////////////////////////////////////////////
01173 //     Function: PNMFileTypePNM::Writer::Constructor
01174 //       Access: Public
01175 //  Description:
01176 ////////////////////////////////////////////////////////////////////
01177 PNMFileTypePNM::Writer::
01178 Writer(PNMFileType *type, ostream *file, bool owns_file) :
01179   PNMWriter(type, file, owns_file)
01180 {
01181 }
01182 
01183 ////////////////////////////////////////////////////////////////////
01184 //     Function: PNMFileTypePNM::Writer::supports_write_row
01185 //       Access: Public, Virtual
01186 //  Description: Returns true if this particular PNMWriter supports a
01187 //               streaming interface to writing the data: that is, it
01188 //               is capable of writing the image one row at a time,
01189 //               via repeated calls to write_row().  Returns false if
01190 //               the only way to write from this file is all at once,
01191 //               via write_data().
01192 ////////////////////////////////////////////////////////////////////
01193 bool PNMFileTypePNM::Writer::
01194 supports_write_row() const {
01195   return true;
01196 }
01197 
01198 ////////////////////////////////////////////////////////////////////
01199 //     Function: PNMFileTypePNM::Writer::write_header
01200 //       Access: Public, Virtual
01201 //  Description: If supports_write_row(), above, returns true, this
01202 //               function may be called to write out the image header
01203 //               in preparation to writing out the image data one row
01204 //               at a time.  Returns true if the header is
01205 //               successfully written, false if there is an error.
01206 //
01207 //               It is the user's responsibility to fill in the header
01208 //               data via calls to set_x_size(), set_num_channels(),
01209 //               etc., or copy_header_from(), before calling
01210 //               write_header().
01211 ////////////////////////////////////////////////////////////////////
01212 bool PNMFileTypePNM::Writer::
01213 write_header() {
01214   switch (get_color_type()) {
01215   case PNMImageHeader::CT_grayscale:
01216   case PNMImageHeader::CT_two_channel:
01217     if (_maxval == 1) {
01218       _pnm_format = PBM_TYPE;
01219     } else {
01220       _pnm_format = PGM_TYPE;
01221     }
01222     break;
01223 
01224   case PNMImageHeader::CT_color:
01225   case PNMImageHeader::CT_four_channel:
01226     _pnm_format = PPM_TYPE;
01227     break;
01228 
01229   default:
01230     break;
01231   }
01232 
01233   pnm_writepnminit(_file, _x_size, _y_size, _maxval, _pnm_format, 0);
01234   return true;
01235 }
01236 
01237 ////////////////////////////////////////////////////////////////////
01238 //     Function: PNMFileTypePNM::Writer::write_row
01239 //       Access: Public, Virtual
01240 //  Description: If supports_write_row(), above, returns true, this
01241 //               function may be called repeatedly to write the image,
01242 //               one horizontal row at a time, beginning from the top.
01243 //               Returns true if the row is successfully written,
01244 //               false if there is an error.
01245 //
01246 //               You must first call write_header() before writing the
01247 //               individual rows.  It is also important to delete the
01248 //               PNMWriter class after successfully writing the last
01249 //               row.  Failing to do this may result in some data not
01250 //               getting flushed!
01251 ////////////////////////////////////////////////////////////////////
01252 bool PNMFileTypePNM::Writer::
01253 write_row(xel *row_data, xelval *) {
01254   pnm_writepnmrow(_file, row_data, _x_size, _maxval, _pnm_format, 0);
01255 
01256   return true;
01257 }
01258 
01259 ////////////////////////////////////////////////////////////////////
01260 //     Function: PNMFileTypePNM::register_with_read_factory
01261 //       Access: Public, Static
01262 //  Description: Registers the current object as something that can be
01263 //               read from a Bam file.
01264 ////////////////////////////////////////////////////////////////////
01265 void PNMFileTypePNM::
01266 register_with_read_factory() {
01267   BamReader::get_factory()->
01268     register_factory(get_class_type(), make_PNMFileTypePNM);
01269 }
01270 
01271 ////////////////////////////////////////////////////////////////////
01272 //     Function: PNMFileTypePNM::make_PNMFileTypePNM
01273 //       Access: Protected, Static
01274 //  Description: This method is called by the BamReader when an object
01275 //               of this type is encountered in a Bam file; it should
01276 //               allocate and return a new object with all the data
01277 //               read.
01278 //
01279 //               In the case of the PNMFileType objects, since these
01280 //               objects are all shared, we just pull the object from
01281 //               the registry.
01282 ////////////////////////////////////////////////////////////////////
01283 TypedWritable *PNMFileTypePNM::
01284 make_PNMFileTypePNM(const FactoryParams &params) {
01285   return PNMFileTypeRegistry::get_global_ptr()->get_type_by_handle(get_class_type());
01286 }
01287 
01288 #endif  // HAVE_PNM
 All Classes Functions Variables Enumerations