15 #include "pnmFileTypePNM.h"
19 #include "config_pnmimagetypes.h"
21 #include "pnmFileTypeRegistry.h"
22 #include "bamReader.h"
24 static const char *
const extensions_PNM[] = {
25 "pbm",
"pgm",
"ppm",
"pnm"
27 static const int num_extensions_PNM =
sizeof(extensions_PNM) /
sizeof(
const char *);
33 #define PBM_MAGIC1 'P'
34 #define PBM_MAGIC2 '1'
35 #define RPBM_MAGIC2 '4'
36 #define PBM_FORMAT (PBM_MAGIC1 * 256 + PBM_MAGIC2)
37 #define RPBM_FORMAT (PBM_MAGIC1 * 256 + RPBM_MAGIC2)
38 #define PBM_TYPE PBM_FORMAT
40 #define PBM_FORMAT_TYPE(f) \
41 ((f) == PBM_FORMAT || (f) == RPBM_FORMAT ? PBM_TYPE : -1)
43 #define PGM_OVERALLMAXVAL 65535
45 #define PGM_MAGIC1 'P'
46 #define PGM_MAGIC2 '2'
47 #define RPGM_MAGIC2 '5'
48 #define PGM_FORMAT (PGM_MAGIC1 * 256 + PGM_MAGIC2)
49 #define RPGM_FORMAT (PGM_MAGIC1 * 256 + RPGM_MAGIC2)
50 #define PGM_TYPE PGM_FORMAT
52 #define PGM_FORMAT_TYPE(f) ((f) == PGM_FORMAT || (f) == RPGM_FORMAT ? PGM_TYPE : PBM_FORMAT_TYPE(f))
54 #define PPM_OVERALLMAXVAL PGM_OVERALLMAXVAL
55 #define PPM_MAXMAXVAL PGM_MAXMAXVAL
57 #define PPM_MAGIC1 'P'
58 #define PPM_MAGIC2 '3'
59 #define RPPM_MAGIC2 '6'
60 #define PPM_FORMAT (PPM_MAGIC1 * 256 + PPM_MAGIC2)
61 #define RPPM_FORMAT (PPM_MAGIC1 * 256 + RPPM_MAGIC2)
62 #define PPM_TYPE PPM_FORMAT
64 #define PPM_FORMAT_TYPE(f) \
65 ((f) == PPM_FORMAT || (f) == RPPM_FORMAT ? PPM_TYPE : PGM_FORMAT_TYPE(f))
67 #define PNM_OVERALLMAXVAL PPM_OVERALLMAXVAL
68 #define PNM_GET1(x) PPM_GETB(x)
70 #define PNM_FORMAT_TYPE(f) PPM_FORMAT_TYPE(f)
72 typedef unsigned char bit;
76 #define pbm_allocarray(cols, rows) \
77 ((bit**) pm_allocarray(cols, rows, sizeof(bit)))
78 #define pbm_allocrow(cols) ((bit*) pm_allocrow(cols, sizeof(bit)))
79 #define pbm_freearray(bits, rows) pm_freearray((char**) bits, rows)
80 #define pbm_freerow(bitrow) pm_freerow((char*) bitrow)
81 #define pbm_packed_bytes(cols) (((cols)+7)/8)
82 #define pbm_allocrow_packed(cols) \
83 ((unsigned char *) pm_allocrow(pbm_packed_bytes(cols), \
84 sizeof(unsigned char)))
85 #define pbm_freerow_packed(packed_bits) \
86 pm_freerow((char *) packed_bits)
87 #define pbm_allocarray_packed(cols, rows) ((unsigned char **) \
88 pm_allocarray(pbm_packed_bytes(cols), rows, sizeof(unsigned char)))
89 #define pbm_freearray_packed(packed_bits, rows) \
90 pm_freearray((char **) packed_bits, rows)
92 #define pgm_allocarray( cols, rows ) ((gray**) pm_allocarray( cols, rows, sizeof(gray) ))
93 #define pgm_allocrow( cols ) ((gray*) pm_allocrow( cols, sizeof(gray) ))
94 #define pgm_freearray( grays, rows ) pm_freearray( (char**) grays, rows )
95 #define pgm_freerow( grayrow ) pm_freerow( (char*) grayrow )
97 #define ppm_allocarray( cols, rows ) ((pixel**) pm_allocarray( cols, rows, sizeof(pixel) ))
98 #define ppm_allocrow( cols ) ((pixel*) pm_allocrow( cols, sizeof(pixel) ))
99 #define ppm_freearray( pixels, rows ) pm_freearray( (char**) pixels, rows )
100 #define ppm_freerow( pixelrow ) pm_freerow( (char*) pixelrow )
102 static const bool pm_plain_output =
false;
108 pm_allocarray(
int const cols,
int const rows,
int const size ) {
130 rowIndex = (
char **)PANDA_MALLOC_ARRAY((rows + 1) *
sizeof(
char *));
131 if ( rowIndex == NULL )
132 pm_error(
"out of memory allocating row index (%u rows) for an array",
134 rowheap = (
char *)PANDA_MALLOC_ARRAY( rows * cols * size );
135 if ( rowheap == NULL ) {
141 rowIndex[rows] = NULL;
143 for (row = 0; row < rows; ++row) {
144 rowIndex[row] = pm_allocrow(cols, size);
145 if (rowIndex[row] == NULL)
146 pm_error(
"out of memory allocating Row %u "
147 "(%u columns, %u bytes per tuple) "
148 "of an array", row, cols, size);
153 rowIndex[rows] = rowheap;
155 for (row = 0; row < rows; ++row)
156 rowIndex[row] = &(rowheap[row * cols * size]);
162 pm_freearray(
char **
const rowIndex,
165 void *
const rowheap = rowIndex[rows];
167 if (rowheap != NULL) {
168 PANDA_FREE_ARRAY(rowheap);
171 for (row = 0; row < rows; ++row) {
172 pm_freerow(rowIndex[row]);
175 PANDA_FREE_ARRAY(rowIndex);
179 pm_getuint(istream *
const ifP) {
204 }
while (ch != EOF && ch !=
'\n');
206 }
while (ch ==
' ' || ch ==
'\t' || ch ==
'\n' || ch ==
'\r');
208 if (ch < '0' || ch >
'9')
209 pm_error(
"junk in file where an unsigned integer should be");
213 unsigned int const digitVal = ch -
'0';
215 if (i > INT_MAX/10 - digitVal)
216 pm_error(
"ASCII decimal integer in file is "
217 "too large to be processed. ");
218 i = i * 10 + digitVal;
220 }
while (ch >=
'0' && ch <=
'9');
226 ppm_readppminitrest(istream *
const file,
229 pixval *
const maxvalP) {
233 *colsP = (int)pm_getuint(file);
234 *rowsP = (int)pm_getuint(file);
237 maxval = pm_getuint(file);
238 if (maxval > PPM_OVERALLMAXVAL)
239 pm_error(
"maxval of input image (%u) is too large. "
240 "The maximum allowed by the PPM is %u.",
241 maxval, PPM_OVERALLMAXVAL);
243 pm_error(
"maxval of input image is zero.");
249 pgm_readpgminitrest(istream *
const file,
252 gray *
const maxvalP) {
257 *colsP = (int)pm_getuint(file);
258 *rowsP = (int)pm_getuint(file);
261 maxval = pm_getuint(file);
262 if (maxval > PGM_OVERALLMAXVAL)
263 pm_error(
"maxval of input image (%u) is too large. "
264 "The maximum allowed by PGM is %u.",
265 maxval, PGM_OVERALLMAXVAL);
267 pm_error(
"maxval of input image is zero.");
273 pbm_readpbminitrest(istream* file,
277 *colsP = (int)pm_getuint( file );
278 *rowsP = (int)pm_getuint( file );
289 pm_error(
"Number of columns in header is too large.");
291 pm_error(
"Number of columns in header is too large.");
295 pm_getrawbyte(istream *
const file) {
300 pm_error(
"EOF / read error reading a one-byte sample");
301 return (
unsigned char) iby;
305 getbit (istream *
const file) {
310 }
while ( ch ==
' ' || ch ==
'\t' || ch ==
'\n' || ch ==
'\r' );
312 if ( ch !=
'0' && ch !=
'1' )
313 pm_error(
"junk in file where bits should be" );
315 return ( ch ==
'1' ) ? 1 : 0;
319 pbm_readpbmrow( istream *file, bit *bitrow,
int cols,
int format ) {
326 for ( col = 0, bP = bitrow; col < cols; ++col, ++bP )
327 *bP = getbit( file );
332 bitshift = -1; item = 0;
333 for ( col = 0, bP = bitrow; col < cols; ++col, ++bP )
335 if ( bitshift == -1 )
337 item = pm_getrawbyte( file );
340 *bP = ( item >> bitshift ) & 1;
347 pm_error(
"can't happen" );
352 pgm_getrawsample(istream *
const file, gray
const maxval) {
356 return(pm_getrawbyte(file));
359 unsigned char byte_pair[2];
362 file->read((
char *)byte_pair, 2);
363 pairs_read = file->gcount();
365 pm_error(
"EOF /read error while reading a long sample");
370 return((byte_pair[0]<<8) | byte_pair[1]);
375 pgm_readpgmrow(istream*
const file, gray*
const grayrow,
376 int const cols, gray
const maxval,
int const format) {
381 for (col = 0; col < cols; ++col) {
382 grayrow[col] = pm_getuint(file);
384 if (grayrow[col] > maxval)
385 pm_error(
"value out of bounds (%u > %u)",
386 grayrow[col], maxval );
394 for (col = 0; col < cols; ++col) {
395 grayrow[col] = pgm_getrawsample( file, maxval );
397 if ( grayrow[col] > maxval )
398 pm_error(
"value out of bounds (%u > %u)",
399 grayrow[col], maxval );
411 bitrow = pbm_allocrow(cols);
412 pbm_readpbmrow( file, bitrow, cols, format );
413 for (col = 0; col < cols; ++col)
414 grayrow[col] = (bitrow[col] == PBM_WHITE ) ? maxval : 0;
420 pm_error(
"can't happen" );
425 ppm_readppmrow(istream*
const fileP,
426 pixel*
const pixelrow,
434 for (col = 0; col < cols; ++col) {
435 pixval
const r = pm_getuint(fileP);
436 pixval
const g = pm_getuint(fileP);
437 pixval
const b = pm_getuint(fileP);
438 PPM_ASSIGN(pixelrow[col], r, g, b);
445 for (col = 0; col < cols; ++col) {
446 pixval
const r = pgm_getrawsample(fileP, maxval);
447 pixval
const g = pgm_getrawsample(fileP, maxval);
448 pixval
const b = pgm_getrawsample(fileP, maxval);
449 PPM_ASSIGN(pixelrow[col], r, g, b);
456 gray *
const grayrow = pgm_allocrow(cols);
459 pgm_readpgmrow(fileP, grayrow, cols, maxval, format);
460 for (col = 0; col < cols; ++col) {
461 pixval
const g = grayrow[col];
462 PPM_ASSIGN(pixelrow[col], g, g, g);
464 pgm_freerow(grayrow);
470 bit *
const bitrow = pbm_allocrow(cols);
473 pbm_readpbmrow(fileP, bitrow, cols, format);
474 for (col = 0; col < cols; ++col) {
475 pixval
const g = (bitrow[col] == PBM_WHITE) ? maxval : 0;
476 PPM_ASSIGN(pixelrow[col], g, g, g);
483 pm_error(
"Invalid format code");
488 pnm_readpnmrow( istream* file,
xel* xelrow,
int cols, xelval maxval,
int format ) {
496 switch ( PNM_FORMAT_TYPE(format) )
499 ppm_readppmrow( file, (
pixel*) xelrow, cols, (pixval) maxval, format );
503 grayrow = pgm_allocrow( cols );
504 pgm_readpgmrow( file, grayrow, cols, (gray) maxval, format );
505 for ( col = 0, xP = xelrow, gP = grayrow; col < cols; ++col, ++xP, ++gP )
506 PNM_ASSIGN1( *xP, *gP );
507 pgm_freerow( grayrow );
511 bitrow = pbm_allocrow( cols );
512 pbm_readpbmrow( file, bitrow, cols, format );
513 for ( col = 0, xP = xelrow, bP = bitrow; col < cols; ++col, ++xP, ++bP )
514 PNM_ASSIGN1( *xP, *bP == PBM_BLACK ? 0: maxval );
515 pbm_freerow( bitrow );
519 pm_error(
"can't happen" );
524 pbm_writepbminit(ostream *
const fileP,
527 int const forceplain) {
529 if (!forceplain && !pm_plain_output) {
534 << cols << ' ' << rows << '\n';
540 << cols << ' ' << rows << '\n';
545 pgm_writepgminit(ostream * const fileP,
549 int const forceplain) {
551 bool const plainFormat = forceplain || pm_plain_output;
553 if (maxval > PGM_OVERALLMAXVAL && !plainFormat)
554 pm_error(
"too-large maxval passed to ppm_writepgminit(): %d.\n"
555 "Maximum allowed by the PGM format is %d.",
556 maxval, PGM_OVERALLMAXVAL);
560 << (
char)(plainFormat ? PGM_MAGIC2 : RPGM_MAGIC2)
562 << cols <<
' ' << rows <<
'\n' << maxval <<
'\n';
566 ppm_writeppminit(ostream*
const fileP,
570 int const forceplain) {
572 bool const plainFormat = forceplain || pm_plain_output;
574 if (maxval > PPM_OVERALLMAXVAL && !plainFormat)
575 pm_error(
"too-large maxval passed to ppm_writeppminit(): %d."
576 "Maximum allowed by the PPM format is %d.",
577 maxval, PPM_OVERALLMAXVAL);
581 << (
char)(plainFormat ? PPM_MAGIC2 : RPPM_MAGIC2)
583 << cols <<
' ' << rows <<
'\n' << maxval <<
'\n';
587 pnm_writepnminit(ostream *
const fileP,
592 int const forceplain) {
594 bool const plainFormat = forceplain || pm_plain_output;
596 switch (PNM_FORMAT_TYPE(format)) {
598 ppm_writeppminit(fileP, cols, rows, (pixval) maxval, plainFormat);
602 pgm_writepgminit(fileP, cols, rows, (gray) maxval, plainFormat);
606 pbm_writepbminit(fileP, cols, rows, plainFormat);
610 pm_error(
"invalid format argument received by pnm_writepnminit(): %d"
611 "PNM_FORMAT_TYPE(format) must be %d, %d, or %d",
612 format, PBM_TYPE, PGM_TYPE, PPM_TYPE);
617 packBitsGeneric(ostream *
const fileP,
618 const bit *
const bitrow,
619 unsigned char *
const packedBits,
621 int *
const nextColP) {
632 #define iszero(x) ((x) == 0 ? 0 : 1)
634 for (col = 0; col + 7 < cols; col += 8)
635 packedBits[col/8] = (
636 iszero(bitrow[col+0]) << 7 |
637 iszero(bitrow[col+1]) << 6 |
638 iszero(bitrow[col+2]) << 5 |
639 iszero(bitrow[col+3]) << 4 |
640 iszero(bitrow[col+4]) << 3 |
641 iszero(bitrow[col+5]) << 2 |
642 iszero(bitrow[col+6]) << 1 |
643 iszero(bitrow[col+7]) << 0
649 writePackedRawRow(ostream *
const fileP,
650 const unsigned char *
const packed_bits,
654 fileP->write((
const char *)packed_bits, pbm_packed_bytes(cols));
656 pm_error(
"I/O error writing packed row to raw PBM file.");
660 writePbmRowRaw(ostream *
const fileP,
661 const bit *
const bitrow,
666 unsigned char *
const packedBits = pbm_allocrow_packed(cols);
668 packBitsGeneric(fileP, bitrow, packedBits, cols, &nextCol);
682 for (col = nextCol; col < cols; ++col, --bitshift )
684 item |= 1 << bitshift
687 packedBits[col/8] = item;
690 writePackedRawRow(fileP, packedBits, cols);
692 pbm_freerow_packed(packedBits);
698 writePbmRowPlain(ostream *
const fileP,
705 for (col = 0; col < cols; ++col) {
706 if (charcount >= 70) {
710 fileP->put(bitrow[col] ?
'1' :
'0');
717 pbm_writepbmrow(ostream *
const fileP,
720 int const forceplain) {
722 if (!forceplain && !pm_plain_output)
723 writePbmRowRaw(fileP, bitrow, cols);
725 writePbmRowPlain(fileP, bitrow, cols);
729 pgm_writerawsample(ostream *file,
const gray val,
const gray maxval) {
735 pm_error(
"Error writing single byte sample to file");
738 unsigned char outval[2];
743 outval[0] = val >> 8;
744 outval[1] = val & 0xFF;
745 file->write((
const char *)outval, 2);
747 pm_error(
"Error writing double byte sample to file");
752 pgm_writepgmrowraw(ostream *file, gray *grayrow,
int cols, gray maxval ) {
755 for (col = 0; col < cols; ++col) {
757 if (grayrow[col] > maxval)
758 pm_error(
"value out of bounds (%u > %u)", grayrow[col], maxval);
760 pgm_writerawsample(file, grayrow[col], maxval);
765 putus(
unsigned short const n,
766 ostream *
const fileP) {
769 putus(n / 10, fileP);
770 fileP->put(n % 10 +
'0');
775 pgm_writepgmrowplain(ostream *
const fileP,
776 gray *
const grayrow,
784 for (col = 0, gP = grayrow; col < cols; ++col, ++gP) {
785 if (charcount >= 65) {
788 }
else if (charcount > 0) {
794 pm_error(
"value out of bounds (%u > %u)", *gP, maxval);
796 putus((
unsigned short)*gP, fileP);
804 pgm_writepgmrow(ostream*
const fileP,
808 int const forceplain) {
810 if (forceplain || pm_plain_output )
811 pgm_writepgmrowplain(fileP, grayrow, cols, maxval);
813 pgm_writepgmrowraw(fileP, grayrow, cols, maxval);
817 ppm_writeppmrowraw(ostream *file,
pixel *pixelrow,
int cols, pixval maxval ) {
821 for ( col = 0; col < cols; ++col )
823 val = PPM_GETR( pixelrow[col] );
826 pm_error(
"r value out of bounds (%u > %u)", val, maxval );
828 pgm_writerawsample( file, val, maxval );
829 val = PPM_GETG( pixelrow[col] );
832 pm_error(
"g value out of bounds (%u > %u)", val, maxval );
834 pgm_writerawsample( file, val, maxval );
835 val = PPM_GETB( pixelrow[col] );
838 pm_error(
"b value out of bounds (%u > %u)", val, maxval );
840 pgm_writerawsample( file, val, maxval );
845 ppm_writeppmrowplain(ostream *file,
pixel *pixelrow,
int cols, pixval maxval ) {
851 for ( col = 0, pP = pixelrow; col < cols; ++col, ++pP )
853 if ( charcount >= 65 )
855 (void) file->put(
'\n' );
858 else if ( charcount > 0 )
860 (void) file->put(
' ' );
861 (void) file->put(
' ' );
864 val = PPM_GETR( *pP );
867 pm_error(
"r value out of bounds (%u > %u)", val, maxval );
870 (void) file->put(
' ' );
871 val = PPM_GETG( *pP );
874 pm_error(
"g value out of bounds (%u > %u)", val, maxval );
877 (void) file->put(
' ' );
878 val = PPM_GETB( *pP );
881 pm_error(
"b value out of bounds (%u > %u)", val, maxval );
887 (void) file->put(
'\n' );
891 ppm_writeppmrow(ostream *
const fileP,
892 pixel *
const pixelrow,
895 int const forceplain) {
897 if (forceplain || pm_plain_output )
898 ppm_writeppmrowplain(fileP, pixelrow, cols, maxval);
900 ppm_writeppmrowraw(fileP, pixelrow, cols, maxval);
904 pnm_writepnmrow(ostream *
const fileP,
909 int const forceplain) {
911 bool const plainFormat = forceplain || pm_plain_output;
913 switch (PNM_FORMAT_TYPE(format)) {
915 ppm_writeppmrow(fileP, (
pixel*) xelrow, cols, (pixval) maxval,
923 grayrow = pgm_allocrow(cols);
925 for (col = 0; col < cols; ++col)
926 grayrow[col] = PNM_GET1(xelrow[col]);
928 pgm_writepgmrow(fileP, grayrow, cols, (gray) maxval, plainFormat);
930 pgm_freerow( grayrow );
938 bitrow = pbm_allocrow(cols);
940 for (col = 0; col < cols; ++col)
941 bitrow[col] = PNM_GET1(xelrow[col]) == 0 ? PBM_BLACK : PBM_WHITE;
943 pbm_writepbmrow(fileP, bitrow, cols, plainFormat);
950 pm_error(
"invalid format argument received by pnm_writepnmrow(): %d"
951 "PNM_FORMAT_TYPE(format) must be %d, %d, or %d",
952 format, PBM_TYPE, PGM_TYPE, PPM_TYPE);
970 string PNMFileTypePNM::
972 return "NetPBM-style PBM/PGM/PPM/PNM";
982 get_num_extensions()
const {
983 return num_extensions_PNM;
993 string PNMFileTypePNM::
994 get_extension(
int n)
const {
995 nassertr(n >= 0 && n < num_extensions_PNM,
string());
996 return extensions_PNM[n];
1006 string PNMFileTypePNM::
1007 get_suggested_extension()
const {
1017 bool PNMFileTypePNM::
1018 has_magic_number()
const {
1029 bool PNMFileTypePNM::
1030 matches_magic_number(
const string &magic_number)
const {
1031 return (magic_number.size() >= 2) &&
1032 magic_number[0] ==
'P' &&
1033 (magic_number[1] >=
'1' && magic_number[1] <=
'6');
1044 make_reader(istream *file,
bool owns_file,
const string &magic_number) {
1046 return new Reader(
this, file, owns_file, magic_number);
1057 make_writer(ostream *file,
bool owns_file) {
1059 return new Writer(
this, file, owns_file);
1068 PNMFileTypePNM::Reader::
1069 Reader(
PNMFileType *type, istream *file,
bool owns_file,
string magic_number) :
1074 if (pnmimage_pnm_cat.is_debug()) {
1075 pnmimage_pnm_cat.debug()
1076 <<
"PNM file appears to be empty.\n";
1083 ((
unsigned char)magic_number[0] << 8) |
1084 (
unsigned char)magic_number[1];
1086 switch ( PNM_FORMAT_TYPE(_ftype) ) {
1088 ppm_readppminitrest( file, &_x_size, &_y_size, &_maxval );
1093 pgm_readpgminitrest( file, &_x_size, &_y_size, &_maxval );
1098 pbm_readpbminitrest( file, &_x_size, &_y_size );
1107 if (pnmimage_pnm_cat.is_debug()) {
1109 pnmimage_pnm_cat.debug()
1111 switch (PNM_FORMAT_TYPE(_ftype)) {
1113 pnmimage_pnm_cat.debug(
false) <<
"PPM";
1116 pnmimage_pnm_cat.debug(
false) <<
"PGM";
1119 pnmimage_pnm_cat.debug(
false) <<
"PBM";
1122 pnmimage_pnm_cat.debug(
false)
1123 <<
" " << *
this <<
"\n";
1125 pnmimage_pnm_cat.debug()
1126 <<
"File is not a valid PNM image.\n";
1141 bool PNMFileTypePNM::Reader::
1142 supports_read_row()
const {
1163 bool PNMFileTypePNM::Reader::
1164 read_row(
xel *array, xelval *,
int x_size,
int y_size) {
1168 pnm_readpnmrow(_file, array, x_size, _maxval, _ftype);
1178 PNMFileTypePNM::Writer::
1179 Writer(
PNMFileType *type, ostream *file,
bool owns_file) :
1194 bool PNMFileTypePNM::Writer::
1195 supports_write_row()
const {
1213 bool PNMFileTypePNM::Writer::
1215 switch (get_color_type()) {
1216 case PNMImageHeader::CT_grayscale:
1217 case PNMImageHeader::CT_two_channel:
1219 _pnm_format = PBM_TYPE;
1221 _pnm_format = PGM_TYPE;
1225 case PNMImageHeader::CT_color:
1226 case PNMImageHeader::CT_four_channel:
1227 _pnm_format = PPM_TYPE;
1234 pnm_writepnminit(_file, _x_size, _y_size, _maxval, _pnm_format, 0);
1253 bool PNMFileTypePNM::Writer::
1254 write_row(
xel *row_data, xelval *) {
1255 pnm_writepnmrow(_file, row_data, _x_size, _maxval, _pnm_format, 0);
1266 void PNMFileTypePNM::
1267 register_with_read_factory() {
1269 register_factory(get_class_type(), make_PNMFileTypePNM);
PNMFileType * get_type_by_handle(TypeHandle handle) const
Returns the PNMFileType instance stored in the registry for the given TypeHandle, e...
Base class for objects that can be written to and read from Bam files.
This is the base class of a family of classes that represent particular image file types that PNMImag...
static PNMFileTypeRegistry * get_global_ptr()
Returns a pointer to the global PNMFileTypeRegistry object.
bool is_valid() const
Returns true if the PNMWriter can be used to write data, false if something is wrong.
An instance of this class is passed to the Factory when requesting it to do its business and construc...
This is an abstract base class that defines the interface for reading image files of various types...
This is an abstract base class that defines the interface for writing image files of various types...
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
TypeHandle is the identifier used to differentiate C++ class types.