Panda3D
pnmFileTypePNM.cxx
1 // Filename: pnmFileTypePNM.cxx
2 // Created by: drose (04Apr98)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "pnmFileTypePNM.h"
16 
17 #ifdef HAVE_PNM
18 
19 #include "config_pnmimagetypes.h"
20 
21 #include "pnmFileTypeRegistry.h"
22 #include "bamReader.h"
23 
24 static const char * const extensions_PNM[] = {
25  "pbm", "pgm", "ppm", "pnm"
26 };
27 static const int num_extensions_PNM = sizeof(extensions_PNM) / sizeof(const char *);
28 
29 TypeHandle PNMFileTypePNM::_type_handle;
30 
31 // Some macros lifted from the original Netpbm sources.
32 
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
39 
40 #define PBM_FORMAT_TYPE(f) \
41  ((f) == PBM_FORMAT || (f) == RPBM_FORMAT ? PBM_TYPE : -1)
42 
43 #define PGM_OVERALLMAXVAL 65535
44 
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
51 
52 #define PGM_FORMAT_TYPE(f) ((f) == PGM_FORMAT || (f) == RPGM_FORMAT ? PGM_TYPE : PBM_FORMAT_TYPE(f))
53 
54 #define PPM_OVERALLMAXVAL PGM_OVERALLMAXVAL
55 #define PPM_MAXMAXVAL PGM_MAXMAXVAL
56 
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
63 
64 #define PPM_FORMAT_TYPE(f) \
65  ((f) == PPM_FORMAT || (f) == RPPM_FORMAT ? PPM_TYPE : PGM_FORMAT_TYPE(f))
66 
67 #define PNM_OVERALLMAXVAL PPM_OVERALLMAXVAL
68 #define PNM_GET1(x) PPM_GETB(x)
69 
70 #define PNM_FORMAT_TYPE(f) PPM_FORMAT_TYPE(f)
71 
72 typedef unsigned char bit;
73 #define PBM_WHITE 0
74 #define PBM_BLACK 1
75 
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)
91 
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 )
96 
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 )
101 
102 static const bool pm_plain_output = false;
103 
104 // Some functions lifted from Netpbm and adapted to use C++ iostreams.
105 
106 
107 char**
108 pm_allocarray(int const cols, int const rows, int const size ) {
109  /*----------------------------------------------------------------------------
110  Allocate an array of 'rows' rows of 'cols' columns each, with each
111  element 'size' bytes.
112 
113  We use a special format where we tack on an extra element to the row
114  index to indicate the format of the array.
115 
116  We have two ways of allocating the space: fragmented and
117  unfragmented. In both, the row index (plus the extra element) is
118  in one block of memory. In the fragmented format, each row is
119  also in an independent memory block, and the extra row pointer is
120  NULL. In the unfragmented format, all the rows are in a single
121  block of memory called the row heap and the extra row pointer is
122  the address of that block.
123 
124  We use unfragmented format if possible, but if the allocation of the
125  row heap fails, we fall back to fragmented.
126  -----------------------------------------------------------------------------*/
127  char** rowIndex;
128  char * rowheap;
129 
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",
133  rows);
134  rowheap = (char *)PANDA_MALLOC_ARRAY( rows * cols * size );
135  if ( rowheap == NULL ) {
136  /* We couldn't get the whole heap in one block, so try fragmented
137  format.
138  */
139  int row;
140 
141  rowIndex[rows] = NULL; /* Declare it fragmented format */
142 
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);
149  }
150  } else {
151  /* It's unfragmented format */
152  int row;
153  rowIndex[rows] = rowheap; /* Declare it unfragmented format */
154 
155  for (row = 0; row < rows; ++row)
156  rowIndex[row] = &(rowheap[row * cols * size]);
157  }
158  return rowIndex;
159 }
160 
161 void
162 pm_freearray(char ** const rowIndex,
163  int const rows) {
164 
165  void * const rowheap = rowIndex[rows];
166 
167  if (rowheap != NULL) {
168  PANDA_FREE_ARRAY(rowheap);
169  } else {
170  int row;
171  for (row = 0; row < rows; ++row) {
172  pm_freerow(rowIndex[row]);
173  }
174  }
175  PANDA_FREE_ARRAY(rowIndex);
176 }
177 
178 static unsigned int
179 pm_getuint(istream * const ifP) {
180  /*----------------------------------------------------------------------------
181  Read an unsigned integer in ASCII decimal from the file stream
182  represented by 'ifP' and return its value.
183 
184  If there is nothing at the current position in the file stream that
185  can be interpreted as an unsigned integer, issue an error message
186  to stderr and abort the program.
187 
188  If the number at the current position in the file stream is too
189  great to be represented by an 'int' (Yes, I said 'int', not
190  'unsigned int'), issue an error message to stderr and abort the
191  program.
192  -----------------------------------------------------------------------------*/
193  char ch;
194  unsigned int i;
195 
196  // skip whitespace
197  do {
198  ch = ifP->get();
199 
200  if (ch == '#') {
201  // Skip a comment
202  do {
203  ch = ifP->get();
204  } while (ch != EOF && ch != '\n');
205  }
206  } while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r');
207 
208  if (ch < '0' || ch > '9')
209  pm_error("junk in file where an unsigned integer should be");
210 
211  i = 0;
212  do {
213  unsigned int const digitVal = ch - '0';
214 
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;
219  ch = ifP->get();
220  } while (ch >= '0' && ch <= '9');
221 
222  return i;
223 }
224 
225 static void
226 ppm_readppminitrest(istream * const file,
227  int * const colsP,
228  int * const rowsP,
229  pixval * const maxvalP) {
230  unsigned int maxval;
231 
232  /* Read size. */
233  *colsP = (int)pm_getuint(file);
234  *rowsP = (int)pm_getuint(file);
235 
236  /* Read maxval. */
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);
242  if (maxval == 0)
243  pm_error("maxval of input image is zero.");
244 
245  *maxvalP = maxval;
246 }
247 
248 static void
249 pgm_readpgminitrest(istream * const file,
250  int * const colsP,
251  int * const rowsP,
252  gray * const maxvalP) {
253 
254  gray maxval;
255 
256  /* Read size. */
257  *colsP = (int)pm_getuint(file);
258  *rowsP = (int)pm_getuint(file);
259 
260  /* Read maxval. */
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);
266  if (maxval == 0)
267  pm_error("maxval of input image is zero.");
268 
269  *maxvalP = maxval;
270 }
271 
272 static void
273 pbm_readpbminitrest(istream* file,
274  int* colsP,
275  int* rowsP) {
276  /* Read size. */
277  *colsP = (int)pm_getuint( file );
278  *rowsP = (int)pm_getuint( file );
279 
280  /* *colsP and *rowsP really should be unsigned int, but they come
281  from the time before unsigned ints (or at least from a person
282  trained in that tradition), so they are int. We could simply
283  consider negative numbers to mean values > INT_MAX/2 and much
284  code would just automatically work. But some code would fail
285  miserably. So we consider values that won't fit in an int to
286  be unprocessable.
287  */
288  if (*colsP < 0)
289  pm_error("Number of columns in header is too large.");
290  if (*rowsP < 0)
291  pm_error("Number of columns in header is too large.");
292 }
293 
294 static unsigned char
295 pm_getrawbyte(istream * const file) {
296  int iby;
297 
298  iby = file->get();
299  if (iby == EOF)
300  pm_error("EOF / read error reading a one-byte sample");
301  return (unsigned char) iby;
302 }
303 
304 static bit
305 getbit (istream * const file) {
306  char ch;
307 
308  do {
309  ch = file->get();
310  } while ( ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' );
311 
312  if ( ch != '0' && ch != '1' )
313  pm_error( "junk in file where bits should be" );
314 
315  return ( ch == '1' ) ? 1 : 0;
316 }
317 
318 static void
319 pbm_readpbmrow( istream *file, bit *bitrow, int cols, int format ) {
320  int col, bitshift;
321  bit* bP;
322 
323  switch ( format )
324  {
325  case PBM_FORMAT:
326  for ( col = 0, bP = bitrow; col < cols; ++col, ++bP )
327  *bP = getbit( file );
328  break;
329 
330  case RPBM_FORMAT: {
331  unsigned char item;
332  bitshift = -1; item = 0; /* item's value is meaningless here */
333  for ( col = 0, bP = bitrow; col < cols; ++col, ++bP )
334  {
335  if ( bitshift == -1 )
336  {
337  item = pm_getrawbyte( file );
338  bitshift = 7;
339  }
340  *bP = ( item >> bitshift ) & 1;
341  --bitshift;
342  }
343  }
344  break;
345 
346  default:
347  pm_error( "can't happen" );
348  }
349 }
350 
351 static gray
352 pgm_getrawsample(istream * const file, gray const maxval) {
353 
354  if (maxval < 256) {
355  /* The sample is just one byte. Read it. */
356  return(pm_getrawbyte(file));
357  } else {
358  /* The sample is two bytes. Read both. */
359  unsigned char byte_pair[2];
360  size_t pairs_read;
361 
362  file->read((char *)byte_pair, 2);
363  pairs_read = file->gcount();
364  if (pairs_read == 0)
365  pm_error("EOF /read error while reading a long sample");
366  /* This could be a few instructions faster if exploited the internal
367  format (i.e. endianness) of a pixval. Then we might be able to
368  skip the shifting and oring.
369  */
370  return((byte_pair[0]<<8) | byte_pair[1]);
371  }
372 }
373 
374 static void
375 pgm_readpgmrow(istream* const file, gray* const grayrow,
376  int const cols, gray const maxval, int const format) {
377 
378  switch (format) {
379  case PGM_FORMAT: {
380  int col;
381  for (col = 0; col < cols; ++col) {
382  grayrow[col] = pm_getuint(file);
383 #ifdef DEBUG
384  if (grayrow[col] > maxval)
385  pm_error( "value out of bounds (%u > %u)",
386  grayrow[col], maxval );
387 #endif /*DEBUG*/
388  }
389  }
390  break;
391 
392  case RPGM_FORMAT: {
393  int col;
394  for (col = 0; col < cols; ++col) {
395  grayrow[col] = pgm_getrawsample( file, maxval );
396 #ifdef DEBUG
397  if ( grayrow[col] > maxval )
398  pm_error( "value out of bounds (%u > %u)",
399  grayrow[col], maxval );
400 #endif /*DEBUG*/
401  }
402  }
403  break;
404 
405  case PBM_FORMAT:
406  case RPBM_FORMAT:
407  {
408  bit * bitrow;
409  int col;
410 
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;
415  pbm_freerow(bitrow);
416  }
417  break;
418 
419  default:
420  pm_error( "can't happen" );
421  }
422 }
423 
424 static void
425 ppm_readppmrow(istream* const fileP,
426  pixel* const pixelrow,
427  int const cols,
428  pixval const maxval,
429  int const format) {
430 
431  switch (format) {
432  case PPM_FORMAT: {
433  int col;
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);
439  }
440  }
441  break;
442 
443  case RPPM_FORMAT: {
444  int col;
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);
450  }
451  }
452  break;
453 
454  case PGM_FORMAT:
455  case RPGM_FORMAT: {
456  gray * const grayrow = pgm_allocrow(cols);
457  int col;
458 
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);
463  }
464  pgm_freerow(grayrow);
465  }
466  break;
467 
468  case PBM_FORMAT:
469  case RPBM_FORMAT: {
470  bit * const bitrow = pbm_allocrow(cols);
471  int col;
472 
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);
477  }
478  pbm_freerow(bitrow);
479  }
480  break;
481 
482  default:
483  pm_error("Invalid format code");
484  }
485 }
486 
487 static void
488 pnm_readpnmrow( istream* file, xel* xelrow, int cols, xelval maxval, int format ) {
489  int col;
490  xel* xP;
491  gray* grayrow;
492  gray* gP;
493  bit* bitrow;
494  bit* bP;
495 
496  switch ( PNM_FORMAT_TYPE(format) )
497  {
498  case PPM_TYPE:
499  ppm_readppmrow( file, (pixel*) xelrow, cols, (pixval) maxval, format );
500  break;
501 
502  case PGM_TYPE:
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 );
508  break;
509 
510  case PBM_TYPE:
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 );
516  break;
517 
518  default:
519  pm_error( "can't happen" );
520  }
521 }
522 
523 static void
524 pbm_writepbminit(ostream * const fileP,
525  int const cols,
526  int const rows,
527  int const forceplain) {
528 
529  if (!forceplain && !pm_plain_output) {
530  (*fileP)
531  << (char)PBM_MAGIC1
532  << (char)RPBM_MAGIC2
533  << '\n'
534  << cols << ' ' << rows << '\n';
535  } else {
536  (*fileP)
537  << (char)PBM_MAGIC1
538  << (char)PBM_MAGIC2
539  << '\n'
540  << cols << ' ' << rows << '\n';
541  }
542 }
543 
544 static void
545 pgm_writepgminit(ostream * const fileP,
546  int const cols,
547  int const rows,
548  gray const maxval,
549  int const forceplain) {
550 
551  bool const plainFormat = forceplain || pm_plain_output;
552 
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);
557 
558  (*fileP)
559  << (char)PGM_MAGIC1
560  << (char)(plainFormat /*|| maxval >= 1<<16*/ ? PGM_MAGIC2 : RPGM_MAGIC2)
561  << '\n'
562  << cols << ' ' << rows << '\n' << maxval << '\n';
563 }
564 
565 static void
566 ppm_writeppminit(ostream* const fileP,
567  int const cols,
568  int const rows,
569  pixval const maxval,
570  int const forceplain) {
571 
572  bool const plainFormat = forceplain || pm_plain_output;
573 
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);
578 
579  (*fileP)
580  << (char)PPM_MAGIC1
581  << (char)(plainFormat /*|| maxval >= 1<<16*/ ? PPM_MAGIC2 : RPPM_MAGIC2)
582  << '\n'
583  << cols << ' ' << rows << '\n' << maxval << '\n';
584 }
585 
586 static void
587 pnm_writepnminit(ostream * const fileP,
588  int const cols,
589  int const rows,
590  xelval const maxval,
591  int const format,
592  int const forceplain) {
593 
594  bool const plainFormat = forceplain || pm_plain_output;
595 
596  switch (PNM_FORMAT_TYPE(format)) {
597  case PPM_TYPE:
598  ppm_writeppminit(fileP, cols, rows, (pixval) maxval, plainFormat);
599  break;
600 
601  case PGM_TYPE:
602  pgm_writepgminit(fileP, cols, rows, (gray) maxval, plainFormat);
603  break;
604 
605  case PBM_TYPE:
606  pbm_writepbminit(fileP, cols, rows, plainFormat);
607  break;
608 
609  default:
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);
613  }
614 }
615 
616 static void
617 packBitsGeneric(ostream * const fileP,
618  const bit * const bitrow,
619  unsigned char * const packedBits,
620  int const cols,
621  int * const nextColP) {
622  /*----------------------------------------------------------------------------
623  Pack the bits of bitrow[] into byts at 'packedBits'. Going left to right,
624  stop when there aren't enough bits left to fill a whole byte. Return
625  as *nextColP the number of the next column after the rightmost one we
626  packed.
627 
628  Don't use any special CPU facilities to do the packing.
629  -----------------------------------------------------------------------------*/
630  int col;
631 
632 #define iszero(x) ((x) == 0 ? 0 : 1)
633 
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
644  );
645  *nextColP = col;
646 }
647 
648 static void
649 writePackedRawRow(ostream * const fileP,
650  const unsigned char * const packed_bits,
651  int const cols) {
652 
653  fileP->write((const char *)packed_bits, pbm_packed_bytes(cols));
654  if (fileP->fail()) {
655  pm_error("I/O error writing packed row to raw PBM file.");
656  }
657 }
658 
659 static void
660 writePbmRowRaw(ostream * const fileP,
661  const bit * const bitrow,
662  int const cols) {
663 
664  int nextCol;
665 
666  unsigned char * const packedBits = pbm_allocrow_packed(cols);
667 
668  packBitsGeneric(fileP, bitrow, packedBits, cols, &nextCol);
669 
670  /* routine for partial byte at the end of packed_bits[]
671  Prior to addition of the above enhancement,
672  this method was used for the entire process
673  */
674 
675  if (cols % 8 > 0) {
676  int col;
677  int bitshift;
678  unsigned char item;
679 
680  bitshift = 7; /* initial value */
681  item = 0; /* initial value */
682  for (col = nextCol; col < cols; ++col, --bitshift )
683  if (bitrow[col] !=0)
684  item |= 1 << bitshift
685  ;
686 
687  packedBits[col/8] = item;
688  }
689 
690  writePackedRawRow(fileP, packedBits, cols);
691 
692  pbm_freerow_packed(packedBits);
693 }
694 
695 
696 
697 static void
698 writePbmRowPlain(ostream * const fileP,
699  bit * const bitrow,
700  int const cols) {
701 
702  int col, charcount;
703 
704  charcount = 0;
705  for (col = 0; col < cols; ++col) {
706  if (charcount >= 70) {
707  fileP->put('\n');
708  charcount = 0;
709  }
710  fileP->put(bitrow[col] ? '1' : '0');
711  ++charcount;
712  }
713  fileP->put('\n');
714 }
715 
716 static void
717 pbm_writepbmrow(ostream * const fileP,
718  bit * const bitrow,
719  int const cols,
720  int const forceplain) {
721 
722  if (!forceplain && !pm_plain_output)
723  writePbmRowRaw(fileP, bitrow, cols);
724  else
725  writePbmRowPlain(fileP, bitrow, cols);
726 }
727 
728 static void
729 pgm_writerawsample(ostream *file, const gray val, const gray maxval) {
730 
731  if (maxval < 256) {
732  /* Samples fit in one byte, so write just one byte */
733  file->put(val);
734  if (file->fail())
735  pm_error("Error writing single byte sample to file");
736  } else {
737  /* Samples are too big for one byte, so write two */
738  unsigned char outval[2];
739  /* We could save a few instructions if we exploited the internal
740  format of a gray, i.e. its endianness. Then we might be able
741  to skip the shifting and anding.
742  */
743  outval[0] = val >> 8;
744  outval[1] = val & 0xFF;
745  file->write((const char *)outval, 2);
746  if (file->fail())
747  pm_error("Error writing double byte sample to file");
748  }
749 }
750 
751 static void
752 pgm_writepgmrowraw(ostream *file, gray *grayrow, int cols, gray maxval ) {
753  int col;
754 
755  for (col = 0; col < cols; ++col) {
756 #ifdef DEBUG
757  if (grayrow[col] > maxval)
758  pm_error( "value out of bounds (%u > %u)", grayrow[col], maxval);
759 #endif /*DEBUG*/
760  pgm_writerawsample(file, grayrow[col], maxval);
761  }
762 }
763 
764 static void
765 putus(unsigned short const n,
766  ostream * const fileP) {
767 
768  if (n >= 10)
769  putus(n / 10, fileP);
770  fileP->put(n % 10 + '0');
771 }
772 
773 
774 static void
775 pgm_writepgmrowplain(ostream * const fileP,
776  gray * const grayrow,
777  int const cols,
778  gray const maxval) {
779 
780  int col, charcount;
781  gray* gP;
782 
783  charcount = 0;
784  for (col = 0, gP = grayrow; col < cols; ++col, ++gP) {
785  if (charcount >= 65) {
786  fileP->put('\n');
787  charcount = 0;
788  } else if (charcount > 0) {
789  fileP->put(' ');
790  ++charcount;
791  }
792 #ifdef DEBUG
793  if (*gP > maxval)
794  pm_error("value out of bounds (%u > %u)", *gP, maxval);
795 #endif /*DEBUG*/
796  putus((unsigned short)*gP, fileP);
797  charcount += 3;
798  }
799  if (charcount > 0)
800  fileP->put('\n');
801 }
802 
803 static void
804 pgm_writepgmrow(ostream* const fileP,
805  gray* const grayrow,
806  int const cols,
807  gray const maxval,
808  int const forceplain) {
809 
810  if (forceplain || pm_plain_output /*|| maxval >= 1<<16*/)
811  pgm_writepgmrowplain(fileP, grayrow, cols, maxval);
812  else
813  pgm_writepgmrowraw(fileP, grayrow, cols, maxval);
814 }
815 
816 static void
817 ppm_writeppmrowraw(ostream *file, pixel *pixelrow, int cols, pixval maxval ) {
818  int col;
819  pixval val;
820 
821  for ( col = 0; col < cols; ++col )
822  {
823  val = PPM_GETR( pixelrow[col] );
824 #ifdef DEBUG
825  if ( val > maxval )
826  pm_error( "r value out of bounds (%u > %u)", val, maxval );
827 #endif /*DEBUG*/
828  pgm_writerawsample( file, val, maxval );
829  val = PPM_GETG( pixelrow[col] );
830 #ifdef DEBUG
831  if ( val > maxval )
832  pm_error( "g value out of bounds (%u > %u)", val, maxval );
833 #endif /*DEBUG*/
834  pgm_writerawsample( file, val, maxval );
835  val = PPM_GETB( pixelrow[col] );
836 #ifdef DEBUG
837  if ( val > maxval )
838  pm_error( "b value out of bounds (%u > %u)", val, maxval );
839 #endif /*DEBUG*/
840  pgm_writerawsample( file, val, maxval );
841  }
842 }
843 
844 static void
845 ppm_writeppmrowplain(ostream *file, pixel *pixelrow, int cols, pixval maxval ) {
846  int col, charcount;
847  pixel* pP;
848  pixval val;
849 
850  charcount = 0;
851  for ( col = 0, pP = pixelrow; col < cols; ++col, ++pP )
852  {
853  if ( charcount >= 65 )
854  {
855  (void) file->put( '\n' );
856  charcount = 0;
857  }
858  else if ( charcount > 0 )
859  {
860  (void) file->put( ' ' );
861  (void) file->put( ' ' );
862  charcount += 2;
863  }
864  val = PPM_GETR( *pP );
865 #ifdef DEBUG
866  if ( val > maxval )
867  pm_error( "r value out of bounds (%u > %u)", val, maxval );
868 #endif /*DEBUG*/
869  putus( val, file );
870  (void) file->put( ' ' );
871  val = PPM_GETG( *pP );
872 #ifdef DEBUG
873  if ( val > maxval )
874  pm_error( "g value out of bounds (%u > %u)", val, maxval );
875 #endif /*DEBUG*/
876  putus( val, file );
877  (void) file->put( ' ' );
878  val = PPM_GETB( *pP );
879 #ifdef DEBUG
880  if ( val > maxval )
881  pm_error( "b value out of bounds (%u > %u)", val, maxval );
882 #endif /*DEBUG*/
883  putus( val, file );
884  charcount += 11;
885  }
886  if ( charcount > 0 )
887  (void) file->put( '\n' );
888 }
889 
890 static void
891 ppm_writeppmrow(ostream * const fileP,
892  pixel * const pixelrow,
893  int const cols,
894  pixval const maxval,
895  int const forceplain) {
896 
897  if (forceplain || pm_plain_output /*|| maxval >= 1<<16*/)
898  ppm_writeppmrowplain(fileP, pixelrow, cols, maxval);
899  else
900  ppm_writeppmrowraw(fileP, pixelrow, cols, maxval);
901 }
902 
903 static void
904 pnm_writepnmrow(ostream * const fileP,
905  xel * const xelrow,
906  int const cols,
907  xelval const maxval,
908  int const format,
909  int const forceplain) {
910 
911  bool const plainFormat = forceplain || pm_plain_output;
912 
913  switch (PNM_FORMAT_TYPE(format)) {
914  case PPM_TYPE:
915  ppm_writeppmrow(fileP, (pixel*) xelrow, cols, (pixval) maxval,
916  plainFormat);
917  break;
918 
919  case PGM_TYPE: {
920  gray* grayrow;
921  int col;
922 
923  grayrow = pgm_allocrow(cols);
924 
925  for (col = 0; col < cols; ++col)
926  grayrow[col] = PNM_GET1(xelrow[col]);
927 
928  pgm_writepgmrow(fileP, grayrow, cols, (gray) maxval, plainFormat);
929 
930  pgm_freerow( grayrow );
931  }
932  break;
933 
934  case PBM_TYPE: {
935  bit* bitrow;
936  int col;
937 
938  bitrow = pbm_allocrow(cols);
939 
940  for (col = 0; col < cols; ++col)
941  bitrow[col] = PNM_GET1(xelrow[col]) == 0 ? PBM_BLACK : PBM_WHITE;
942 
943  pbm_writepbmrow(fileP, bitrow, cols, plainFormat);
944 
945  pbm_freerow(bitrow);
946  }
947  break;
948 
949  default:
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);
953  }
954 }
955 
956 ////////////////////////////////////////////////////////////////////
957 // Function: PNMFileTypePNM::Constructor
958 // Access: Public
959 // Description:
960 ////////////////////////////////////////////////////////////////////
961 PNMFileTypePNM::
962 PNMFileTypePNM() {
963 }
964 
965 ////////////////////////////////////////////////////////////////////
966 // Function: PNMFileTypePNM::get_name
967 // Access: Public, Virtual
968 // Description: Returns a few words describing the file type.
969 ////////////////////////////////////////////////////////////////////
970 string PNMFileTypePNM::
971 get_name() const {
972  return "NetPBM-style PBM/PGM/PPM/PNM";
973 }
974 
975 ////////////////////////////////////////////////////////////////////
976 // Function: PNMFileTypePNM::get_num_extensions
977 // Access: Public, Virtual
978 // Description: Returns the number of different possible filename
979 // extensions_PNM associated with this particular file type.
980 ////////////////////////////////////////////////////////////////////
981 int PNMFileTypePNM::
982 get_num_extensions() const {
983  return num_extensions_PNM;
984 }
985 
986 ////////////////////////////////////////////////////////////////////
987 // Function: PNMFileTypePNM::get_extension
988 // Access: Public, Virtual
989 // Description: Returns the nth possible filename extension
990 // associated with this particular file type, without a
991 // leading dot.
992 ////////////////////////////////////////////////////////////////////
993 string PNMFileTypePNM::
994 get_extension(int n) const {
995  nassertr(n >= 0 && n < num_extensions_PNM, string());
996  return extensions_PNM[n];
997 }
998 
999 ////////////////////////////////////////////////////////////////////
1000 // Function: PNMFileTypePNM::get_suggested_extension
1001 // Access: Public, Virtual
1002 // Description: Returns a suitable filename extension (without a
1003 // leading dot) to suggest for files of this type, or
1004 // empty string if no suggestions are available.
1005 ////////////////////////////////////////////////////////////////////
1006 string PNMFileTypePNM::
1007 get_suggested_extension() const {
1008  return "ppm";
1009 }
1010 
1011 ////////////////////////////////////////////////////////////////////
1012 // Function: PNMFileTypePNM::has_magic_number
1013 // Access: Public, Virtual
1014 // Description: Returns true if this particular file type uses a
1015 // magic number to identify it, false otherwise.
1016 ////////////////////////////////////////////////////////////////////
1017 bool PNMFileTypePNM::
1018 has_magic_number() const {
1019  return true;
1020 }
1021 
1022 ////////////////////////////////////////////////////////////////////
1023 // Function: PNMFileTypePNM::matches_magic_number
1024 // Access: Public, Virtual
1025 // Description: Returns true if the indicated "magic number" byte
1026 // stream (the initial few bytes read from the file)
1027 // matches this particular file type, false otherwise.
1028 ////////////////////////////////////////////////////////////////////
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');
1034 }
1035 
1036 ////////////////////////////////////////////////////////////////////
1037 // Function: PNMFileTypePNM::make_reader
1038 // Access: Public, Virtual
1039 // Description: Allocates and returns a new PNMReader suitable for
1040 // reading from this file type, if possible. If reading
1041 // from this file type is not supported, returns NULL.
1042 ////////////////////////////////////////////////////////////////////
1043 PNMReader *PNMFileTypePNM::
1044 make_reader(istream *file, bool owns_file, const string &magic_number) {
1045  init_pnm();
1046  return new Reader(this, file, owns_file, magic_number);
1047 }
1048 
1049 ////////////////////////////////////////////////////////////////////
1050 // Function: PNMFileTypePNM::make_writer
1051 // Access: Public, Virtual
1052 // Description: Allocates and returns a new PNMWriter suitable for
1053 // reading from this file type, if possible. If writing
1054 // files of this type is not supported, returns NULL.
1055 ////////////////////////////////////////////////////////////////////
1056 PNMWriter *PNMFileTypePNM::
1057 make_writer(ostream *file, bool owns_file) {
1058  init_pnm();
1059  return new Writer(this, file, owns_file);
1060 }
1061 
1062 
1063 ////////////////////////////////////////////////////////////////////
1064 // Function: PNMFileTypePNM::Reader::Constructor
1065 // Access: Public
1066 // Description:
1067 ////////////////////////////////////////////////////////////////////
1068 PNMFileTypePNM::Reader::
1069 Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number) :
1070  PNMReader(type, file, owns_file)
1071 {
1072  if (!read_magic_number(_file, magic_number, 2)) {
1073  // No magic number. No image.
1074  if (pnmimage_pnm_cat.is_debug()) {
1075  pnmimage_pnm_cat.debug()
1076  << "PNM file appears to be empty.\n";
1077  }
1078  _is_valid = false;
1079  return;
1080  }
1081 
1082  _ftype =
1083  ((unsigned char)magic_number[0] << 8) |
1084  (unsigned char)magic_number[1];
1085 
1086  switch ( PNM_FORMAT_TYPE(_ftype) ) {
1087  case PPM_TYPE:
1088  ppm_readppminitrest( file, &_x_size, &_y_size, &_maxval );
1089  _num_channels = 3;
1090  break;
1091 
1092  case PGM_TYPE:
1093  pgm_readpgminitrest( file, &_x_size, &_y_size, &_maxval );
1094  _num_channels = 1;
1095  break;
1096 
1097  case PBM_TYPE:
1098  pbm_readpbminitrest( file, &_x_size, &_y_size );
1099  _num_channels = 1;
1100  _maxval = 1;
1101  break;
1102 
1103  default:
1104  _is_valid = false;
1105  }
1106 
1107  if (pnmimage_pnm_cat.is_debug()) {
1108  if (is_valid()) {
1109  pnmimage_pnm_cat.debug()
1110  << "Reading ";
1111  switch (PNM_FORMAT_TYPE(_ftype)) {
1112  case PPM_TYPE:
1113  pnmimage_pnm_cat.debug(false) << "PPM";
1114  break;
1115  case PGM_TYPE:
1116  pnmimage_pnm_cat.debug(false) << "PGM";
1117  break;
1118  case PBM_TYPE:
1119  pnmimage_pnm_cat.debug(false) << "PBM";
1120  break;
1121  }
1122  pnmimage_pnm_cat.debug(false)
1123  << " " << *this << "\n";
1124  } else {
1125  pnmimage_pnm_cat.debug()
1126  << "File is not a valid PNM image.\n";
1127  }
1128  }
1129 }
1130 
1131 ////////////////////////////////////////////////////////////////////
1132 // Function: PNMFileTypePNM::Reader::supports_read_row
1133 // Access: Public, Virtual
1134 // Description: Returns true if this particular PNMReader supports a
1135 // streaming interface to reading the data: that is, it
1136 // is capable of returning the data one row at a time,
1137 // via repeated calls to read_row(). Returns false if
1138 // the only way to read from this file is all at once,
1139 // via read_data().
1140 ////////////////////////////////////////////////////////////////////
1141 bool PNMFileTypePNM::Reader::
1142 supports_read_row() const {
1143  return true;
1144 }
1145 
1146 ////////////////////////////////////////////////////////////////////
1147 // Function: PNMFileTypePNM::Reader::read_row
1148 // Access: Public, Virtual
1149 // Description: If supports_read_row(), above, returns true, this
1150 // function may be called repeatedly to read the image,
1151 // one horizontal row at a time, beginning from the top.
1152 // Returns true if the row is successfully read, false
1153 // if there is an error or end of file.
1154 //
1155 // The x_size and y_size parameters are the value of
1156 // _x_size and _y_size as originally filled in by the
1157 // constructor; it is the actual number of pixels in the
1158 // image. (The _x_size and _y_size members may have
1159 // been automatically modified by the time this method
1160 // is called if we are scaling on load, so should not be
1161 // used.)
1162 ////////////////////////////////////////////////////////////////////
1163 bool PNMFileTypePNM::Reader::
1164 read_row(xel *array, xelval *, int x_size, int y_size) {
1165  if (!is_valid()) {
1166  return false;
1167  }
1168  pnm_readpnmrow(_file, array, x_size, _maxval, _ftype);
1169  return true;
1170 }
1171 
1172 
1173 ////////////////////////////////////////////////////////////////////
1174 // Function: PNMFileTypePNM::Writer::Constructor
1175 // Access: Public
1176 // Description:
1177 ////////////////////////////////////////////////////////////////////
1178 PNMFileTypePNM::Writer::
1179 Writer(PNMFileType *type, ostream *file, bool owns_file) :
1180  PNMWriter(type, file, owns_file)
1181 {
1182 }
1183 
1184 ////////////////////////////////////////////////////////////////////
1185 // Function: PNMFileTypePNM::Writer::supports_write_row
1186 // Access: Public, Virtual
1187 // Description: Returns true if this particular PNMWriter supports a
1188 // streaming interface to writing the data: that is, it
1189 // is capable of writing the image one row at a time,
1190 // via repeated calls to write_row(). Returns false if
1191 // the only way to write from this file is all at once,
1192 // via write_data().
1193 ////////////////////////////////////////////////////////////////////
1194 bool PNMFileTypePNM::Writer::
1195 supports_write_row() const {
1196  return true;
1197 }
1198 
1199 ////////////////////////////////////////////////////////////////////
1200 // Function: PNMFileTypePNM::Writer::write_header
1201 // Access: Public, Virtual
1202 // Description: If supports_write_row(), above, returns true, this
1203 // function may be called to write out the image header
1204 // in preparation to writing out the image data one row
1205 // at a time. Returns true if the header is
1206 // successfully written, false if there is an error.
1207 //
1208 // It is the user's responsibility to fill in the header
1209 // data via calls to set_x_size(), set_num_channels(),
1210 // etc., or copy_header_from(), before calling
1211 // write_header().
1212 ////////////////////////////////////////////////////////////////////
1213 bool PNMFileTypePNM::Writer::
1214 write_header() {
1215  switch (get_color_type()) {
1216  case PNMImageHeader::CT_grayscale:
1217  case PNMImageHeader::CT_two_channel:
1218  if (_maxval == 1) {
1219  _pnm_format = PBM_TYPE;
1220  } else {
1221  _pnm_format = PGM_TYPE;
1222  }
1223  break;
1224 
1225  case PNMImageHeader::CT_color:
1226  case PNMImageHeader::CT_four_channel:
1227  _pnm_format = PPM_TYPE;
1228  break;
1229 
1230  default:
1231  break;
1232  }
1233 
1234  pnm_writepnminit(_file, _x_size, _y_size, _maxval, _pnm_format, 0);
1235  return true;
1236 }
1237 
1238 ////////////////////////////////////////////////////////////////////
1239 // Function: PNMFileTypePNM::Writer::write_row
1240 // Access: Public, Virtual
1241 // Description: If supports_write_row(), above, returns true, this
1242 // function may be called repeatedly to write the image,
1243 // one horizontal row at a time, beginning from the top.
1244 // Returns true if the row is successfully written,
1245 // false if there is an error.
1246 //
1247 // You must first call write_header() before writing the
1248 // individual rows. It is also important to delete the
1249 // PNMWriter class after successfully writing the last
1250 // row. Failing to do this may result in some data not
1251 // getting flushed!
1252 ////////////////////////////////////////////////////////////////////
1253 bool PNMFileTypePNM::Writer::
1254 write_row(xel *row_data, xelval *) {
1255  pnm_writepnmrow(_file, row_data, _x_size, _maxval, _pnm_format, 0);
1256 
1257  return true;
1258 }
1259 
1260 ////////////////////////////////////////////////////////////////////
1261 // Function: PNMFileTypePNM::register_with_read_factory
1262 // Access: Public, Static
1263 // Description: Registers the current object as something that can be
1264 // read from a Bam file.
1265 ////////////////////////////////////////////////////////////////////
1266 void PNMFileTypePNM::
1267 register_with_read_factory() {
1269  register_factory(get_class_type(), make_PNMFileTypePNM);
1270 }
1271 
1272 ////////////////////////////////////////////////////////////////////
1273 // Function: PNMFileTypePNM::make_PNMFileTypePNM
1274 // Access: Protected, Static
1275 // Description: This method is called by the BamReader when an object
1276 // of this type is encountered in a Bam file; it should
1277 // allocate and return a new object with all the data
1278 // read.
1279 //
1280 // In the case of the PNMFileType objects, since these
1281 // objects are all shared, we just pull the object from
1282 // the registry.
1283 ////////////////////////////////////////////////////////////////////
1284 TypedWritable *PNMFileTypePNM::
1285 make_PNMFileTypePNM(const FactoryParams &params) {
1286  return PNMFileTypeRegistry::get_global_ptr()->get_type_by_handle(get_class_type());
1287 }
1288 
1289 #endif // HAVE_PNM
bool is_valid() const
Returns true if the PNMWriter can be used to write data, false if something is wrong.
Definition: pnmWriter.I:114
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:37
This is the base class of a family of classes that represent particular image file types that PNMImag...
Definition: pnmFileType.h:35
static bool read_magic_number(istream *file, string &magic_number, int num_bytes)
Ensures that the first n bytes of the file are read into magic_number.
static PNMFileTypeRegistry * get_global_ptr()
Returns a pointer to the global PNMFileTypeRegistry object.
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:40
PNMFileType * get_type_by_handle(TypeHandle handle) const
Returns the PNMFileType instance stored in the registry for the given TypeHandle, e...
This is an abstract base class that defines the interface for reading image files of various types...
Definition: pnmReader.h:31
This is an abstract base class that defines the interface for writing image files of various types...
Definition: pnmWriter.h:31
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:213
ColorType get_color_type() const
Returns the image type of the image, as an enumerated value.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85