00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
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
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
00105
00106
00107 char**
00108 pm_allocarray(int const cols, int const rows, int const size ) {
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
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
00137
00138
00139 unsigned int row;
00140
00141 rowIndex[rows] = NULL;
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
00152 unsigned int row;
00153 rowIndex[rows] = rowheap;
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
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192 char ch;
00193 unsigned int i;
00194
00195
00196 do {
00197 ch = ifP->get();
00198
00199 if (ch == '#') {
00200
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
00232 *colsP = (int)pm_getuint(file);
00233 *rowsP = (int)pm_getuint(file);
00234
00235
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
00256 *colsP = (int)pm_getuint(file);
00257 *rowsP = (int)pm_getuint(file);
00258
00259
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
00276 *colsP = (int)pm_getuint( file );
00277 *rowsP = (int)pm_getuint( file );
00278
00279
00280
00281
00282
00283
00284
00285
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;
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
00355 return(pm_getrawbyte(file));
00356 } else {
00357
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
00366
00367
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
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
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
00623
00624
00625
00626
00627
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
00670
00671
00672
00673
00674 if (cols % 8 > 0) {
00675 int col;
00676 int bitshift;
00677 unsigned char item;
00678
00679 bitshift = 7;
00680 item = 0;
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
00732 file->put(val);
00733 if (file->fail())
00734 pm_error("Error writing single byte sample to file");
00735 } else {
00736
00737 unsigned char outval[2];
00738
00739
00740
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
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
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
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
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
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
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
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
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
00957
00958
00959
00960 PNMFileTypePNM::
00961 PNMFileTypePNM() {
00962 }
00963
00964
00965
00966
00967
00968
00969 string PNMFileTypePNM::
00970 get_name() const {
00971 return "NetPBM-style PBM/PGM/PPM/PNM";
00972 }
00973
00974
00975
00976
00977
00978
00979
00980 int PNMFileTypePNM::
00981 get_num_extensions() const {
00982 return num_extensions_PNM;
00983 }
00984
00985
00986
00987
00988
00989
00990
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
01000
01001
01002
01003
01004
01005 string PNMFileTypePNM::
01006 get_suggested_extension() const {
01007 return "ppm";
01008 }
01009
01010
01011
01012
01013
01014
01015
01016 bool PNMFileTypePNM::
01017 has_magic_number() const {
01018 return true;
01019 }
01020
01021
01022
01023
01024
01025
01026
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
01037
01038
01039
01040
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
01050
01051
01052
01053
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
01064
01065
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
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
01132
01133
01134
01135
01136
01137
01138
01139
01140 bool PNMFileTypePNM::Reader::
01141 supports_read_row() const {
01142 return true;
01143 }
01144
01145
01146
01147
01148
01149
01150
01151
01152
01153
01154
01155
01156
01157
01158
01159
01160
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
01174
01175
01176
01177 PNMFileTypePNM::Writer::
01178 Writer(PNMFileType *type, ostream *file, bool owns_file) :
01179 PNMWriter(type, file, owns_file)
01180 {
01181 }
01182
01183
01184
01185
01186
01187
01188
01189
01190
01191
01192
01193 bool PNMFileTypePNM::Writer::
01194 supports_write_row() const {
01195 return true;
01196 }
01197
01198
01199
01200
01201
01202
01203
01204
01205
01206
01207
01208
01209
01210
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
01239
01240
01241
01242
01243
01244
01245
01246
01247
01248
01249
01250
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
01261
01262
01263
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
01273
01274
01275
01276
01277
01278
01279
01280
01281
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