Panda3D
|
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 ¶ms) { 01285 return PNMFileTypeRegistry::get_global_ptr()->get_type_by_handle(get_class_type()); 01286 } 01287 01288 #endif // HAVE_PNM