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