Panda3D
 All Classes Functions Variables Enumerations
pnmFileTypeTIFF.cxx
1 // Filename: pnmFileTypeTIFF.cxx
2 // Created by: drose (19Jun00)
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 "pnmFileTypeTIFF.h"
16 
17 #ifdef HAVE_TIFF
18 
19 #include "config_pnmimagetypes.h"
20 
21 #include "pnmFileTypeRegistry.h"
22 #include "bamReader.h"
23 #include "ppmcmap.h"
24 #include "pfmFile.h"
25 
26 // Tiff will want to re-typedef these things.
27 #define int8 tiff_int8
28 #define uint8 tiff_uint8
29 #define int32 tiff_int32
30 #define uint32 tiff_uint32
31 
32 extern "C" {
33 #include <tiff.h>
34 #include <tiffio.h>
35 }
36 
37 static const char * const extensions_tiff[] = {
38  "tiff", "tif"
39 };
40 static const int num_extensions_tiff = sizeof(extensions_tiff) / sizeof(const char *);
41 
42 // These are configurable parameters to specify TIFF details on
43 // output. See tiff.h or type man pnmtotiff for a better explanation
44 // of options.
45 
46 //unsigned short tiff_compression = COMPRESSION_LZW; // lzw not supported anymore because of big bad Unisys
47 unsigned short tiff_compression = COMPRESSION_NONE;
48 
49 /* One of:
50  COMPRESSION_NONE
51  COMPRESSION_CCITTRLE
52  COMPRESSION_CCITTFAX3
53  COMPRESSION_CCITTFAX4
54  COMPRESSION_LZW
55  COMPRESSION_JPEG
56  COMPRESSION_NEXT
57  COMPRESSION_CCITTRLEW
58  COMPRESSION_PACKBITS
59  COMPRESSION_THUNDERSCAN
60  */
61 
62 long tiff_g3options = 0;
63 /* One or more of:
64  GROUP3OPT_2DENCODING
65  GROUP3OPT_FILLBITS
66 
67  meaningful when tiff_compression == COMPRESSION_CCITTFAX3.
68  */
69 
70 unsigned short tiff_fillorder = FILLORDER_MSB2LSB;
71 /* One of:
72  FILLORDER_MSB2LSB
73  FILLORDER_LSB2MSB
74  */
75 
76 short tiff_predictor = 0;
77 /* 0, 1, or 2; meaningful when tiff_compression == COMPRESSION_LZW. */
78 
79 
80 #ifndef PHOTOMETRIC_DEPTH
81 #define PHOTOMETRIC_DEPTH 32768
82 #endif
83 
84 // Here's a number of functions to support the iostream interface
85 // via the TIFF library.
86 static tsize_t
87 istream_read(thandle_t fd, tdata_t buf, tsize_t size) {
88  istream *in = (istream *)fd;
89  in->read((char *)buf, size);
91  return in->gcount();
92 }
93 
94 static tsize_t
95 ostream_write(thandle_t fd, tdata_t buf, tsize_t size) {
96  ostream *out = (ostream *)fd;
97  out->write((char *)buf, size);
99  return out->fail() ? (tsize_t)0 : size;
100 }
101 
102 static tsize_t
103 ostream_dont_read(thandle_t, tdata_t, tsize_t) {
104  // This no-op variant of istream_read() is passed in when we open the
105  // file for writing only. Shouldn't mix reads and writes.
106  return 0;
107 }
108 
109 static tsize_t
110 istream_dont_write(thandle_t, tdata_t, tsize_t) {
111  // This no-op variant of ostream_write() is passed in when we open the
112  // file for reading only. Shouldn't mix reads and writes.
113  return 0;
114 }
115 
116 static toff_t
117 istream_seek(thandle_t fd, toff_t off, int whence) {
118  istream *in = (istream *)fd;
119 
120  ios_seekdir dir;
121  switch (whence) {
122  case SEEK_SET:
123  dir = ios::beg;
124  break;
125 
126  case SEEK_END:
127  dir = ios::end;
128  break;
129 
130  case SEEK_CUR:
131  dir = ios::cur;
132  break;
133 
134  default:
135  return in->tellg();
136  }
137 
138  in->seekg(off, dir);
139 
140  if (pnmimage_tiff_cat->is_spam()) {
141  pnmimage_tiff_cat->spam()
142  << "istream_seek(" << (void *)in << ", " << off << ", "
143  << whence << "), result = " << in->tellg() << "\n";
144  }
145  return in->tellg();
146 }
147 
148 static toff_t
149 ostream_seek(thandle_t fd, toff_t off, int whence) {
150  ostream *out = (ostream *)fd;
151 
152  ios_seekdir dir;
153  switch (whence) {
154  case SEEK_SET:
155  dir = ios::beg;
156  break;
157 
158  case SEEK_END:
159  dir = ios::end;
160  break;
161 
162  case SEEK_CUR:
163  dir = ios::cur;
164  break;
165 
166  default:
167  return out->tellp();
168  }
169 
170  out->seekp(off, dir);
171 
172  if (pnmimage_tiff_cat->is_spam()) {
173  pnmimage_tiff_cat->spam()
174  << "ostream_seek(" << (void *)out << ", " << off << ", "
175  << whence << "), result = " << out->tellp() << "\n";
176  }
177  return out->tellp();
178 }
179 
180 static int
181 iostream_dont_close(thandle_t) {
182  // We don't actually close the file; we'll leave that to PNMReader.
183  return true;
184 }
185 
186 static toff_t
187 istream_size(thandle_t fd) {
188  istream *in = (istream *)fd;
189  in->seekg(0, ios::end);
190  return in->tellg();
191 }
192 
193 static toff_t
194 ostream_size(thandle_t fd) {
195  ostream *out = (ostream *)fd;
196  out->seekp(0, ios::end);
197  return out->tellp();
198 }
199 
200 static int
201 iostream_map(thandle_t, tdata_t*, toff_t*) {
202  return (0);
203 }
204 
205 static void
206 iostream_unmap(thandle_t, tdata_t, toff_t) {
207 }
208 
209 bool PNMFileTypeTIFF::_installed_error_handlers = false;
210 TypeHandle PNMFileTypeTIFF::_type_handle;
211 
212 ////////////////////////////////////////////////////////////////////
213 // Function: PNMFileTypeTIFF::Constructor
214 // Access: Public
215 // Description:
216 ////////////////////////////////////////////////////////////////////
217 PNMFileTypeTIFF::
218 PNMFileTypeTIFF() {
219  // This constructor may run at static init time, so we use the ->
220  // dereferencing convention on the notify category.
221  if (pnmimage_tiff_cat->is_debug()) {
222  pnmimage_tiff_cat->debug()
223  << TIFFGetVersion() << "\n";
224  }
225 }
226 
227 ////////////////////////////////////////////////////////////////////
228 // Function: PNMFileTypeTIFF::get_name
229 // Access: Public, Virtual
230 // Description: Returns a few words describing the file type.
231 ////////////////////////////////////////////////////////////////////
232 string PNMFileTypeTIFF::
233 get_name() const {
234  return "TIFF";
235 }
236 
237 ////////////////////////////////////////////////////////////////////
238 // Function: PNMFileTypeTIFF::get_num_extensions
239 // Access: Public, Virtual
240 // Description: Returns the number of different possible filename
241 // extensions associated with this particular file type.
242 ////////////////////////////////////////////////////////////////////
243 int PNMFileTypeTIFF::
244 get_num_extensions() const {
245  return num_extensions_tiff;
246 }
247 
248 ////////////////////////////////////////////////////////////////////
249 // Function: PNMFileTypeTIFF::get_extension
250 // Access: Public, Virtual
251 // Description: Returns the nth possible filename extension
252 // associated with this particular file type, without a
253 // leading dot.
254 ////////////////////////////////////////////////////////////////////
255 string PNMFileTypeTIFF::
256 get_extension(int n) const {
257  nassertr(n >= 0 && n < num_extensions_tiff, string());
258  return extensions_tiff[n];
259 }
260 
261 ////////////////////////////////////////////////////////////////////
262 // Function: PNMFileTypeTIFF::get_suggested_extension
263 // Access: Public, Virtual
264 // Description: Returns a suitable filename extension (without a
265 // leading dot) to suggest for files of this type, or
266 // empty string if no suggestions are available.
267 ////////////////////////////////////////////////////////////////////
268 string PNMFileTypeTIFF::
269 get_suggested_extension() const {
270  return "tiff";
271 }
272 
273 ////////////////////////////////////////////////////////////////////
274 // Function: PNMFileTypeTIFF::has_magic_number
275 // Access: Public, Virtual
276 // Description: Returns true if this particular file type uses a
277 // magic number to identify it, false otherwise.
278 ////////////////////////////////////////////////////////////////////
279 bool PNMFileTypeTIFF::
280 has_magic_number() const {
281  return true;
282 }
283 
284 ////////////////////////////////////////////////////////////////////
285 // Function: PNMFileTypeTIFF::matches_magic_number
286 // Access: Public, Virtual
287 // Description: Returns true if the indicated "magic number" byte
288 // stream (the initial few bytes read from the file)
289 // matches this particular file type, false otherwise.
290 ////////////////////////////////////////////////////////////////////
291 bool PNMFileTypeTIFF::
292 matches_magic_number(const string &magic_number) const {
293  nassertr(magic_number.size() >= 2, false);
294  int mn =
295  ((unsigned char)magic_number[0] << 8) |
296  ((unsigned char)magic_number[1]);
297  return (mn == TIFF_BIGENDIAN || mn == TIFF_LITTLEENDIAN);
298 }
299 
300 ////////////////////////////////////////////////////////////////////
301 // Function: PNMFileTypeTIFF::make_reader
302 // Access: Public, Virtual
303 // Description: Allocates and returns a new PNMReader suitable for
304 // reading from this file type, if possible. If reading
305 // from this file type is not supported, returns NULL.
306 ////////////////////////////////////////////////////////////////////
307 PNMReader *PNMFileTypeTIFF::
308 make_reader(istream *file, bool owns_file, const string &magic_number) {
309  init_pnm();
310  install_error_handlers();
311  return new Reader(this, file, owns_file, magic_number);
312 }
313 
314 ////////////////////////////////////////////////////////////////////
315 // Function: PNMFileTypeTIFF::make_writer
316 // Access: Public, Virtual
317 // Description: Allocates and returns a new PNMWriter suitable for
318 // reading from this file type, if possible. If writing
319 // files of this type is not supported, returns NULL.
320 ////////////////////////////////////////////////////////////////////
321 PNMWriter *PNMFileTypeTIFF::
322 make_writer(ostream *file, bool owns_file) {
323  init_pnm();
324  install_error_handlers();
325  return new Writer(this, file, owns_file);
326 }
327 
328 ////////////////////////////////////////////////////////////////////
329 // Function: PNMFileTypeTIFF::Reader::Constructor
330 // Access: Public
331 // Description:
332 ////////////////////////////////////////////////////////////////////
333 PNMFileTypeTIFF::Reader::
334 Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number) :
335  PNMReader(type, file, owns_file)
336 {
337  bool grayscale = false;
338  int numcolors;
339  int i;
340  unsigned short* redcolormap;
341  unsigned short* greencolormap;
342  unsigned short* bluecolormap;
343 
344  // Hope we can putback() more than one character.
345  for (string::reverse_iterator mi = magic_number.rbegin();
346  mi != magic_number.rend();
347  mi++) {
348  _file->putback(*mi);
349  }
350  if (_file->fail()) {
351  pnmimage_tiff_cat.error()
352  << "Unable to put back magic number.\n";
353  _is_valid = false;
354  }
355 
356  if (_is_valid) {
357  tif = TIFFClientOpen("TIFF file", "r",
358  (thandle_t) _file,
359  istream_read, istream_dont_write,
360  (TIFFSeekProc)istream_seek,
361  iostream_dont_close, istream_size,
362  iostream_map, iostream_unmap);
363 
364  if ( tif == NULL ) {
365  _is_valid = false;
366  }
367  }
368 
369  if (_is_valid) {
370  if ( ! TIFFGetField( tif, TIFFTAG_SAMPLEFORMAT, &sample_format ) )
371  sample_format = SAMPLEFORMAT_UINT;
372  if ( ! TIFFGetField( tif, TIFFTAG_BITSPERSAMPLE, &bps ) )
373  bps = 1;
374  if ( ! TIFFGetField( tif, TIFFTAG_SAMPLESPERPIXEL, &spp ) )
375  spp = 1;
376 
377  if ( ! TIFFGetField( tif, TIFFTAG_PHOTOMETRIC, &photomet ) ) {
378  pnmimage_tiff_cat.error()
379  << "Error getting photometric from TIFF file.\n";
380  _is_valid = false;
381 
382  } else if (sample_format == SAMPLEFORMAT_IEEEFP) {
383  // Floating-point TIFF. We only accept 32-bit floats.
384  if (bps != 32) {
385  pnmimage_tiff_cat.error()
386  << "Can only read 32-bit float TIFF files, not " << bps << "-bit.\n";
387  _is_valid = false;
388  }
389 
390  } else if (sample_format != SAMPLEFORMAT_UINT) {
391  // Can't understand other kinds of sample formats.
392  pnmimage_tiff_cat.error()
393  << "Can't understand sample format\n";
394  _is_valid = false;
395  }
396  }
397 
398  if (_is_valid) {
399  unsigned short num_extra_samples;
400  unsigned short *extra_samples = NULL;
401 
402  if (!TIFFGetField(tif, TIFFTAG_EXTRASAMPLES, &num_extra_samples,
403  &extra_samples)) {
404  num_extra_samples = 0;
405  }
406  _num_channels = spp - num_extra_samples;
407  unassoc_alpha_sample = 0;
408  assoc_alpha_sample = 0;
409 
410  if (_num_channels == 1 || _num_channels == 3) {
411  // Look for an alpha channel in one of the extra samples, if
412  // any.
413  bool got_alpha = false;
414  for (unsigned short s = 0; s < num_extra_samples && !got_alpha; s++) {
415  if (extra_samples[s] == EXTRASAMPLE_UNASSALPHA) {
416  unassoc_alpha_sample = s + _num_channels;
417  _num_channels++;
418  got_alpha = true;
419 
420  } else if (extra_samples[s] == EXTRASAMPLE_ASSOCALPHA) {
421  assoc_alpha_sample = s + _num_channels;
422  _num_channels++;
423  got_alpha = true;
424  }
425  }
426 
427  // Unfortunately, Photoshop seems to write
428  // EXTRASAMPLE_UNSPECIFIED into the EXTRASAMPLES field for its
429  // alpha channels. If we have exactly one extra channel and
430  // it's an UNSPECIFIED channel, assume it's meant to be alpha.
431  if (!got_alpha && num_extra_samples == 1 &&
432  extra_samples[0] == EXTRASAMPLE_UNSPECIFIED) {
433  unassoc_alpha_sample = _num_channels;
434  _num_channels++;
435  }
436 
437  } else if ((_num_channels == 2 || _num_channels == 4) && num_extra_samples == 0) {
438  // If we have a 2- or 4-channel image but the extra samples are
439  // not declared, assume it was written out by a broken TIFF
440  // implementation and that the extra channel is really meant to
441  // be alpha.
442  unassoc_alpha_sample = _num_channels - 1;
443  if (pnmimage_tiff_cat.is_debug()) {
444  pnmimage_tiff_cat.debug()
445  << "Assuming last channel of " << spp
446  << "-color image is meant to represent alpha.\n";
447  }
448 
449  } else {
450  pnmimage_tiff_cat.error()
451  << "Cannot handle " << spp << "-color image (with "
452  << num_extra_samples << " extra channels).\n";
453  _is_valid = false;
454  }
455  }
456 
457  if (_is_valid) {
458  (void) TIFFGetField( tif, TIFFTAG_IMAGEWIDTH, &_x_size );
459  (void) TIFFGetField( tif, TIFFTAG_IMAGELENGTH, &_y_size );
460 
461  if (pnmimage_tiff_cat.is_debug()) {
462  pnmimage_tiff_cat.debug()
463  << "Reading TIFF image: " << _x_size << " x " << _y_size << "\n"
464  << bps << " bits/sample, " << spp << " samples/pixel\n";
465  }
466 
467  _maxval = ( 1 << bps ) - 1;
468  if ( _maxval == 1 && _num_channels == 1 ) {
469  if (pnmimage_tiff_cat.is_debug()) {
470  pnmimage_tiff_cat.debug(false)
471  << "monochrome\n";
472  }
473  grayscale = true;
474  } else {
475  switch ( photomet ) {
476  case PHOTOMETRIC_MINISBLACK:
477  if (pnmimage_tiff_cat.is_debug()) {
478  pnmimage_tiff_cat.debug(false)
479  << _maxval + 1 << " graylevels (min is black)\n";
480  }
481  grayscale = true;
482  break;
483 
484  case PHOTOMETRIC_MINISWHITE:
485  if (pnmimage_tiff_cat.is_debug()) {
486  pnmimage_tiff_cat.debug(false)
487  << _maxval + 1 << " graylevels (min is white)\n";
488  }
489  grayscale = true;
490  break;
491 
492  case PHOTOMETRIC_PALETTE:
493  if (pnmimage_tiff_cat.is_debug()) {
494  pnmimage_tiff_cat.debug(false)
495  << " colormapped\n";
496  }
497  if ( ! TIFFGetField( tif, TIFFTAG_COLORMAP, &redcolormap, &greencolormap, &bluecolormap ) ) {
498  pnmimage_tiff_cat.error()
499  << "Error getting colormap from TIFF file.\n";
500  _is_valid = false;
501  } else {
502  numcolors = _maxval + 1;
503  if ( numcolors > TIFF_COLORMAP_MAXCOLORS ) {
504  pnmimage_tiff_cat.error()
505  << "Cannot read TIFF file with " << numcolors
506  << " in colormap; max supported is " << TIFF_COLORMAP_MAXCOLORS << "\n";
507  _is_valid = false;
508  } else {
509  _maxval = PNM_MAXMAXVAL;
510  grayscale = false;
511  for ( i = 0; i < numcolors; ++i ) {
512  xelval r, g, b;
513  r = (xelval)(_maxval * (double)(redcolormap[i] / 65535.0));
514  g = (xelval)(_maxval * (double)(greencolormap[i] / 65535.0));
515  b = (xelval)(_maxval * (double)(bluecolormap[i] / 65535.0));
516  PPM_ASSIGN( colormap[i], r, g, b );
517  }
518  }
519  }
520  break;
521 
522  case PHOTOMETRIC_RGB:
523  if (pnmimage_tiff_cat.is_debug()) {
524  pnmimage_tiff_cat.debug(false)
525  << "truecolor\n";
526  }
527  grayscale = false;
528  break;
529 
530  case PHOTOMETRIC_MASK:
531  pnmimage_tiff_cat.error()
532  << "Don't know how to handle TIFF image with PHOTOMETRIC_MASK.\n";
533  _is_valid = false;
534  break;
535 
536  case PHOTOMETRIC_DEPTH:
537  pnmimage_tiff_cat.error()
538  << "Don't know how to handle TIFF image with PHOTOMETRIC_DEPTH.\n";
539  _is_valid = false;
540  break;
541 
542  default:
543  pnmimage_tiff_cat.error()
544  << "Unknown photometric " << photomet << " in TIFF image.\n";
545  _is_valid = false;
546  break;
547  }
548  }
549  }
550 
551  if (_is_valid ) {
552  if ( _maxval > PNM_MAXMAXVAL ) {
553  pnmimage_tiff_cat.error()
554  << "Cannot read TIFF file with maxval of " << _maxval << "\n";
555  _is_valid = false;
556  }
557  }
558 
559  if (_is_valid) {
560  if (grayscale && !is_grayscale()) {
561  _num_channels = (has_alpha()) ? 2 : 1;
562  } else if (!grayscale && is_grayscale()) {
563  _num_channels = (has_alpha()) ? 4 : 3;
564  }
565 
566  current_row = 0;
567  }
568 }
569 
570 ////////////////////////////////////////////////////////////////////
571 // Function: PNMFileTypeTIFF::Reader::Destructor
572 // Access: Public, Virtual
573 // Description:
574 ////////////////////////////////////////////////////////////////////
575 PNMFileTypeTIFF::Reader::
576 ~Reader() {
577  if (tif != (struct tiff *)NULL) {
578  TIFFClose(tif);
579  }
580 }
581 
582 ////////////////////////////////////////////////////////////////////
583 // Function: PNMFileTypeTIFF::Reader::is_floating_point
584 // Access: Public, Virtual
585 // Description: Returns true if this PNMFileType represents a
586 // floating-point image type, false if it is a normal,
587 // integer type. If this returns true, read_pfm() is
588 // implemented instead of read_data().
589 ////////////////////////////////////////////////////////////////////
590 bool PNMFileTypeTIFF::Reader::
591 is_floating_point() {
592  return (sample_format == SAMPLEFORMAT_IEEEFP);
593 }
594 
595 ////////////////////////////////////////////////////////////////////
596 // Function: PNMFileTypeTIFF::Reader::read_pfm
597 // Access: Public, Virtual
598 // Description: Reads floating-point data directly into the indicated
599 // PfmFile. Returns true on success, false on failure.
600 ////////////////////////////////////////////////////////////////////
601 bool PNMFileTypeTIFF::Reader::
602 read_pfm(PfmFile &pfm) {
603  if (!is_valid()) {
604  return false;
605  }
606 
607  int x_size = get_x_size();
608  int y_size = get_y_size();
609  int num_channels = get_num_channels();
610 
611  pfm.clear(x_size, y_size, num_channels);
612  vector_float table;
613  pfm.swap_table(table);
614 
615  for (int yi = 0; yi < y_size; ++yi) {
616  float *row = &table[(yi * x_size) * _num_channels];
617 
618  if (TIFFReadScanline(tif, row, yi, 0 ) < 0 ) {
619  pnmimage_tiff_cat.error()
620  << "failed a scanline read on row " << yi << "\n";
621  pfm.swap_table(table);
622  return false;
623  }
624  }
625 
626  pfm.swap_table(table);
627  return true;
628 }
629 
630 ////////////////////////////////////////////////////////////////////
631 // Function: PNMFileTypeTIFF::Reader::supports_read_row
632 // Access: Public, Virtual
633 // Description: Returns true if this particular PNMReader supports a
634 // streaming interface to reading the data: that is, it
635 // is capable of returning the data one row at a time,
636 // via repeated calls to read_row(). Returns false if
637 // the only way to read from this file is all at once,
638 // via read_data().
639 ////////////////////////////////////////////////////////////////////
640 bool PNMFileTypeTIFF::Reader::
641 supports_read_row() const {
642  return true;
643 }
644 
645 ////////////////////////////////////////////////////////////////////
646 // Function: PNMFileTypeTIFF::Reader::read_row
647 // Access: Public, Virtual
648 // Description: If supports_read_row(), above, returns true, this
649 // function may be called repeatedly to read the image,
650 // one horizontal row at a time, beginning from the top.
651 // Returns true if the row is successfully read, false
652 // if there is an error or end of file.
653 ////////////////////////////////////////////////////////////////////
654 bool PNMFileTypeTIFF::Reader::
655 read_row(xel *row_data, xelval *alpha_data, int x_size, int) {
656  if (!is_valid()) {
657  return false;
658  }
659 
660  size_t scanline_size = (size_t)TIFFScanlineSize(tif);
661  unsigned char *buf = (unsigned char*) alloca(scanline_size);
662 
663  int col;
664  xelval gray, sample;
665  xelval r, g, b;
666 
667  if ( TIFFReadScanline( tif, buf, current_row, 0 ) < 0 ) {
668  pnmimage_tiff_cat.error()
669  << "Bad data read on line " << current_row << " of TIFF image.\n";
670  return false;
671  }
672 
673  unsigned char *buf_ptr = buf;
674  unsigned s;
675  int bits_left = 8;
676 
677  // Get a pointer to a function that extracts the next bps-bit sample
678  // from the bitarray. There are a handful of different functions,
679  // which are optimized for different values of bps.
680  xelval (PNMFileTypeTIFF::Reader::*next_sample)(unsigned char *&buf_ptr, int &bits_left) const;
681 
682  if (bps < 8) {
683  next_sample = &PNMFileTypeTIFF::Reader::next_sample_lt_8;
684 
685  } else if (bps == 8) {
686  next_sample = &PNMFileTypeTIFF::Reader::next_sample_8;
687 
688  } else if (bps == 16) {
689  next_sample = &PNMFileTypeTIFF::Reader::next_sample_16;
690 
691  } else if (bps == 32) {
692  // Actually, it's not likely that a 32-bit sample will fit within
693  // a xelval. Deal with this when we come to it.
694  next_sample = &PNMFileTypeTIFF::Reader::next_sample_32;
695 
696  } else {
697  next_sample = &PNMFileTypeTIFF::Reader::next_sample_general;
698  }
699 
700  switch ( photomet ) {
701  case PHOTOMETRIC_MINISBLACK:
702  for ( col = 0; col < x_size; ++col )
703  {
704  sample = (this->*next_sample)(buf_ptr, bits_left);
705  gray = sample;
706 
707  for (s = 1; s < spp; s++) {
708  sample = (this->*next_sample)(buf_ptr, bits_left);
709  if (s == unassoc_alpha_sample) {
710  alpha_data[col] = sample;
711 
712  } else if (s == assoc_alpha_sample) {
713  alpha_data[col] = sample;
714  if (sample != 0) {
715  gray = (xelval)((float)gray * _maxval / (float)sample);
716  }
717  }
718  }
719  PPM_PUTB(row_data[col], gray);
720  }
721  break;
722 
723  case PHOTOMETRIC_MINISWHITE:
724  for ( col = 0; col < x_size; ++col )
725  {
726  sample = (this->*next_sample)(buf_ptr, bits_left);
727  gray = _maxval - sample;
728  for (s = 1; s < spp; s++) {
729  sample = (this->*next_sample)(buf_ptr, bits_left);
730  sample = _maxval - sample;
731 
732  if (s == unassoc_alpha_sample) {
733  alpha_data[col] = sample;
734 
735  } else if (s == assoc_alpha_sample) {
736  alpha_data[col] = sample;
737  if (sample != 0) {
738  gray = (xelval)((float)gray * _maxval / (float)sample);
739  }
740  }
741  }
742 
743  PPM_PUTB(row_data[col], gray);
744  }
745  break;
746 
747  case PHOTOMETRIC_PALETTE:
748  for ( col = 0; col < x_size; ++col )
749  {
750  sample = (this->*next_sample)(buf_ptr, bits_left);
751  row_data[col] = colormap[sample];
752 
753  for (s = 1; s < spp; s++) {
754  sample = (this->*next_sample)(buf_ptr, bits_left);
755  if (s == unassoc_alpha_sample) {
756  alpha_data[col] = sample;
757 
758  } else if (s == assoc_alpha_sample) {
759  alpha_data[col] = sample;
760  if (sample != 0) {
761  r = PPM_GETR(row_data[col]);
762  g = PPM_GETG(row_data[col]);
763  b = PPM_GETB(row_data[col]);
764  r = (xelval)((float)r * _maxval / (float)sample);
765  g = (xelval)((float)g * _maxval / (float)sample);
766  b = (xelval)((float)b * _maxval / (float)sample);
767  PPM_ASSIGN(row_data[col], r, g, b);
768  }
769  }
770  }
771  }
772  break;
773 
774  case PHOTOMETRIC_RGB:
775  for ( col = 0; col < x_size; ++col ) {
776  sample = (this->*next_sample)(buf_ptr, bits_left);
777  r = sample;
778  sample = (this->*next_sample)(buf_ptr, bits_left);
779  g = sample;
780  sample = (this->*next_sample)(buf_ptr, bits_left);
781  b = sample;
782 
783  for (s = 3; s < spp; s++) {
784  sample = (this->*next_sample)(buf_ptr, bits_left);
785  if (s == unassoc_alpha_sample) {
786  alpha_data[col] = sample;
787 
788  } else if (s == assoc_alpha_sample) {
789  alpha_data[col] = sample;
790  if (sample != 0) {
791  r = (xelval)((float)r * _maxval / (float)sample);
792  g = (xelval)((float)g * _maxval / (float)sample);
793  b = (xelval)((float)b * _maxval / (float)sample);
794  }
795  }
796  }
797 
798  PPM_ASSIGN(row_data[col], r, g, b);
799  }
800  break;
801 
802  default:
803  pnmimage_tiff_cat.error()
804  << "Internal error: unsupported photometric " << photomet << "\n";
805  return false;
806  }
807 
808  nassertr(buf_ptr <= buf + scanline_size, false);
809 
810  current_row++;
811  return true;
812 }
813 
814 ////////////////////////////////////////////////////////////////////
815 // Function: PNMFileTypeTIFF::Reader::next_sample_lt_8
816 // Access: Private
817 // Description: Returns the next color sample from the row, when it
818 // is known that bps < 8.
819 ////////////////////////////////////////////////////////////////////
820 xelval PNMFileTypeTIFF::Reader::
821 next_sample_lt_8(unsigned char *&buf_ptr, int &bits_left) const {
822  if (bits_left == 0) {
823  ++buf_ptr;
824  bits_left = 8;
825  }
826 
827  bits_left -= bps;
828  return (*buf_ptr >> bits_left) & _maxval;
829 }
830 
831 ////////////////////////////////////////////////////////////////////
832 // Function: PNMFileTypeTIFF::Reader::next_sample_8
833 // Access: Private
834 // Description: Returns the next color sample from the row, when it
835 // is known that bps == 8.
836 ////////////////////////////////////////////////////////////////////
837 xelval PNMFileTypeTIFF::Reader::
838 next_sample_8(unsigned char *&buf_ptr, int &bits_left) const {
839  return *buf_ptr++;
840 }
841 
842 ////////////////////////////////////////////////////////////////////
843 // Function: PNMFileTypeTIFF::Reader::next_sample_16
844 // Access: Private
845 // Description: Returns the next color sample from the row, when it
846 // is known that bps == 16.
847 ////////////////////////////////////////////////////////////////////
848 xelval PNMFileTypeTIFF::Reader::
849 next_sample_16(unsigned char *&buf_ptr, int &bits_left) const {
850  // The TIFF library has already byte-swapped the values if
851  // necessary. Thus, we only need to treat it as an array of shorts.
852  unsigned short result = *(unsigned short *)buf_ptr;
853  buf_ptr += 2;
854  return result;
855 }
856 
857 ////////////////////////////////////////////////////////////////////
858 // Function: PNMFileTypeTIFF::Reader::next_sample_32
859 // Access: Private
860 // Description: Returns the next color sample from the row, when it
861 // is known that bps == 32.
862 ////////////////////////////////////////////////////////////////////
863 xelval PNMFileTypeTIFF::Reader::
864 next_sample_32(unsigned char *&buf_ptr, int &bits_left) const {
865  // The TIFF library has already byte-swapped the values if
866  // necessary. Thus, we only need to treat it as an array of longs.
867  unsigned long result = *(unsigned long *)buf_ptr;
868  buf_ptr += 2;
869  return (xelval)result;
870 }
871 
872 ////////////////////////////////////////////////////////////////////
873 // Function: PNMFileTypeTIFF::Reader::next_sample_general
874 // Access: Private
875 // Description: Returns the next color sample from the row, in
876 // general. This unpacks an arbitrary string of bits
877 // from the sequence.
878 ////////////////////////////////////////////////////////////////////
879 xelval PNMFileTypeTIFF::Reader::
880 next_sample_general(unsigned char *&buf_ptr, int &bits_left) const {
881  unsigned int result = 0;
882  int bits_needed = bps;
883 
884  while (bits_needed > 0) {
885  nassertr(bits_left >= 0, 0);
886  if (bits_left == 0) {
887  ++buf_ptr;
888  bits_left = 8;
889  }
890 
891  if (bits_needed <= bits_left) {
892  bits_left -= bits_needed;
893  unsigned int mask = (1 << bits_needed) - 1;
894  result |= ((*buf_ptr) >> bits_left) & mask;
895  bits_needed = 0;
896 
897  } else {
898  bits_needed -= bits_left;
899  unsigned int mask = (1 << bits_left) - 1;
900  result |= ((*buf_ptr) & mask) << bits_needed;
901  bits_left = 0;
902  }
903  }
904 
905  return result;
906 }
907 
908 
909 ////////////////////////////////////////////////////////////////////
910 // Function: PNMFileTypeTIFF::Writer::Constructor
911 // Access: Public
912 // Description:
913 ////////////////////////////////////////////////////////////////////
914 PNMFileTypeTIFF::Writer::
915 Writer(PNMFileType *type, ostream *file, bool owns_file) :
916  PNMWriter(type, file, owns_file)
917 {
918 }
919 
920 ////////////////////////////////////////////////////////////////////
921 // Function: PNMFileTypeTIFF::Writer::supports_floating_point
922 // Access: Public, Virtual
923 // Description: Returns true if this PNMFileType can accept a
924 // floating-point image type, false if it can only
925 // accept a normal, integer type. If this returns true,
926 // write_pfm() is implemented.
927 ////////////////////////////////////////////////////////////////////
928 bool PNMFileTypeTIFF::Writer::
929 supports_floating_point() {
930  return true;
931 }
932 
933 ////////////////////////////////////////////////////////////////////
934 // Function: PNMFileTypeTIFF::Writer::supports_integer
935 // Access: Public, Virtual
936 // Description: Returns true if this PNMFileType can accept an
937 // integer image type, false if it can only
938 // accept a floating-point type. If this returns true,
939 // write_data() or write_row() is implemented.
940 ////////////////////////////////////////////////////////////////////
941 bool PNMFileTypeTIFF::Writer::
942 supports_integer() {
943  return true;
944 }
945 
946 ////////////////////////////////////////////////////////////////////
947 // Function: PNMFileTypeTIFF::Writer::write_pfm
948 // Access: Public, Virtual
949 // Description: Writes floating-point data from the indicated
950 // PfmFile. Returns true on success, false on failure.
951 ////////////////////////////////////////////////////////////////////
952 bool PNMFileTypeTIFF::Writer::
953 write_pfm(const PfmFile &pfm) {
954  struct tiff *tif;
955 
956  // Open output file.
957  tif = TIFFClientOpen("TIFF file", "w",
958  (thandle_t) _file,
959  ostream_dont_read, ostream_write,
960  (TIFFSeekProc)ostream_seek,
961  iostream_dont_close, ostream_size,
962  iostream_map, iostream_unmap);
963  if (tif == NULL) {
964  return false;
965  }
966 
967  int x_size = pfm.get_x_size();
968  int y_size = pfm.get_y_size();
969  int num_channels = pfm.get_num_channels();
970 
971  int photometric = 0;
972  if (num_channels >= 3) {
973  photometric = PHOTOMETRIC_RGB;
974  }
975 
976  // Set TIFF parameters.
977  TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, x_size);
978  TIFFSetField(tif, TIFFTAG_IMAGELENGTH, y_size);
979  TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP);
980  TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 32);
981  TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
982  TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, photometric);
983  TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
984  TIFFSetField(tif, TIFFTAG_IMAGEDESCRIPTION, "Generated via pnmimage.\n" );
985  TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, num_channels);
986  TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
987 
988  const vector_float &table = pfm.get_table();
989  for (int yi = 0; yi < y_size; ++yi) {
990  const float *row = &table[(yi * x_size) * _num_channels];
991 
992  if (TIFFWriteScanline(tif, (tdata_t)row, yi, 0 ) < 0) {
993  pnmimage_tiff_cat.error()
994  << "failed a scanline write on row " << yi << "\n";
995  return false;
996  }
997  }
998 
999  TIFFFlushData(tif);
1000  TIFFClose(tif);
1001 
1002  return true;
1003 }
1004 
1005 ////////////////////////////////////////////////////////////////////
1006 // Function: PNMFileTypeTIFF::Writer::write_data
1007 // Access: Public, Virtual
1008 // Description: Writes out an entire image all at once, including the
1009 // header, based on the image data stored in the given
1010 // _x_size * _y_size array and alpha pointers. (If the
1011 // image type has no alpha channel, alpha is ignored.)
1012 // Returns the number of rows correctly written.
1013 //
1014 // It is the user's responsibility to fill in the header
1015 // data via calls to set_x_size(), set_num_channels(),
1016 // etc., or copy_header_from(), before calling
1017 // write_data().
1018 //
1019 // It is important to delete the PNMWriter class after
1020 // successfully writing the data. Failing to do this
1021 // may result in some data not getting flushed!
1022 //
1023 // Derived classes need not override this if they
1024 // instead provide supports_streaming() and write_row(),
1025 // below.
1026 ////////////////////////////////////////////////////////////////////
1027 int PNMFileTypeTIFF::Writer::
1028 write_data(xel *array, xelval *alpha) {
1030  colorhash_table cht;
1031  unsigned short
1032  red[TIFF_COLORMAP_MAXCOLORS],
1033  grn[TIFF_COLORMAP_MAXCOLORS],
1034  blu[TIFF_COLORMAP_MAXCOLORS];
1035  int row, colors, i;
1036  int col;
1037  int grayscale = false;
1038  struct tiff * tif;
1039  short photometric = 0;
1040  short samplesperpixel = 0;
1041  unsigned short extra_samples[1] = { EXTRASAMPLE_UNASSALPHA };
1042  short bitspersample = 0;
1043  int bytesperrow = 0;
1044  unsigned char* buf;
1045  unsigned char* tP;
1046 
1047  switch ( get_color_type() ) {
1048  case CT_color:
1049  // This call is a bit of fakery to convert our proper 2-d array of
1050  // xels to an indirect 2-d array of pixels. We make it look like a
1051  // single row of _x_size * _y_size pixels.
1052 
1053  // We can't actually write palettes bigger than 256 colors,
1054  // regardless of the number of colors we can read.
1055  chv = ppm_computecolorhist( (pixel **)&array, _x_size * _y_size, 1,
1056  256, &colors );
1057  if ( chv == (colorhist_vector) 0 ) {
1058  pnmimage_tiff_cat.debug()
1059  << colors << " colors found; too many for a palette.\n"
1060  << "Writing a 24-bit RGB file.\n";
1061  grayscale = false;
1062  } else {
1063  pnmimage_tiff_cat.debug()
1064  << colors << " colors found; writing an 8-bit palette file.\n";
1065  grayscale = true;
1066  for ( i = 0; i < colors; ++i ) {
1067  xelval r, g, b;
1068 
1069  r = PPM_GETR( chv[i].color );
1070  g = PPM_GETG( chv[i].color );
1071  b = PPM_GETB( chv[i].color );
1072  if ( r != g || g != b ) {
1073  grayscale = false;
1074  break;
1075  }
1076  }
1077  }
1078  break;
1079 
1080  case CT_two_channel: // We don't yet support two-channel output for TIFF's.
1081  case CT_four_channel:
1082  chv = (colorhist_vector) 0;
1083  grayscale = false;
1084  break;
1085 
1086  case CT_grayscale:
1087  chv = (colorhist_vector) 0;
1088  grayscale = true;
1089  break;
1090 
1091  default:
1092  break;
1093  }
1094 
1095  /* Open output file. */
1096  tif = TIFFClientOpen("TIFF file", "w",
1097  (thandle_t) _file,
1098  ostream_dont_read, ostream_write,
1099  (TIFFSeekProc)ostream_seek,
1100  iostream_dont_close, ostream_size,
1101  iostream_map, iostream_unmap);
1102  if ( tif == NULL ) {
1103  return 0;
1104  }
1105 
1106  /* Figure out TIFF parameters. */
1107  switch ( get_color_type() ) {
1108  case CT_color:
1109  case CT_four_channel:
1110  if ( chv == (colorhist_vector) 0 ) {
1111  samplesperpixel = _num_channels;
1112  bitspersample = 8;
1113  photometric = PHOTOMETRIC_RGB;
1114  bytesperrow = _x_size * samplesperpixel;
1115  } else if ( grayscale ) {
1116  samplesperpixel = 1;
1117  bitspersample = pm_maxvaltobits( _maxval );
1118  photometric = PHOTOMETRIC_MINISBLACK;
1119  i = 8 / bitspersample;
1120  bytesperrow = ( _x_size + i - 1 ) / i;
1121  } else {
1122  samplesperpixel = 1;
1123  bitspersample = 8;
1124  photometric = PHOTOMETRIC_PALETTE;
1125  bytesperrow = _x_size;
1126  }
1127  break;
1128 
1129  case CT_grayscale:
1130  case CT_two_channel:
1131  samplesperpixel = _num_channels;
1132  bitspersample = pm_maxvaltobits( _maxval );
1133  photometric = PHOTOMETRIC_MINISBLACK;
1134  i = 8 / bitspersample;
1135  bytesperrow = ( _x_size + i - 1 ) / i;
1136  break;
1137 
1138  default:
1139  break;
1140  }
1141 
1142  buf = (unsigned char*) malloc( bytesperrow );
1143  if ( buf == (unsigned char*) 0 ) {
1144  pnmimage_tiff_cat.error()
1145  << "Can't allocate memory for row buffer\n";
1146  return 0;
1147  }
1148 
1149  /* Set TIFF parameters. */
1150  TIFFSetField( tif, TIFFTAG_IMAGEWIDTH, _x_size );
1151  TIFFSetField( tif, TIFFTAG_IMAGELENGTH, _y_size );
1152  TIFFSetField( tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT );
1153  TIFFSetField( tif, TIFFTAG_BITSPERSAMPLE, bitspersample );
1154  TIFFSetField( tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT );
1155  TIFFSetField( tif, TIFFTAG_COMPRESSION, tiff_compression );
1156  if ( tiff_compression == COMPRESSION_CCITTFAX3 && tiff_g3options != 0 )
1157  TIFFSetField( tif, TIFFTAG_GROUP3OPTIONS, tiff_g3options );
1158  if ( tiff_compression == COMPRESSION_LZW && tiff_predictor != 0 )
1159  TIFFSetField( tif, TIFFTAG_PREDICTOR, tiff_predictor );
1160  TIFFSetField( tif, TIFFTAG_PHOTOMETRIC, photometric );
1161  TIFFSetField( tif, TIFFTAG_FILLORDER, tiff_fillorder );
1162  //TIFFSetField( tif, TIFFTAG_DOCUMENTNAME, "TIFF Image File");
1163  TIFFSetField( tif, TIFFTAG_IMAGEDESCRIPTION,
1164  "Generated via pnmimage.\n" );
1165  TIFFSetField( tif, TIFFTAG_SAMPLESPERPIXEL, samplesperpixel );
1166  if (has_alpha()) {
1167  TIFFSetField(tif, TIFFTAG_EXTRASAMPLES, 1, extra_samples);
1168  }
1169  TIFFSetField( tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG );
1170 
1171  if ( chv == (colorhist_vector) 0 ) {
1172  cht = (colorhash_table) 0;
1173  } else {
1174  /* Make TIFF colormap. */
1175  for ( i = 0; i < colors; ++i ) {
1176  red[i] = (unsigned short) (PPM_GETR( chv[i].color ) * 65535L / _maxval);
1177  grn[i] = (unsigned short) (PPM_GETG( chv[i].color ) * 65535L / _maxval);
1178  blu[i] = (unsigned short) (PPM_GETB( chv[i].color ) * 65535L / _maxval);
1179  }
1180  TIFFSetField( tif, TIFFTAG_COLORMAP, red, grn, blu );
1181 
1182  /* Convert color vector to color hash table, for fast lookup. */
1183  cht = ppm_colorhisttocolorhash( chv, colors );
1184  ppm_freecolorhist( chv );
1185  }
1186 
1187  /* Now write the TIFF data. */
1188  for ( row = 0; row < _y_size; ++row ) {
1189  xel *row_data = array + row*_x_size;
1190  xelval *alpha_data = alpha + row*_x_size;
1191 
1192  if ( !is_grayscale() && ! grayscale ) {
1193  if ( cht == (colorhash_table) 0 ) {
1194  tP = buf;
1195  for ( col = 0; col < _x_size; ++col ) {
1196  *tP++ = (unsigned char)(255 * PPM_GETR(row_data[col]) / _maxval);
1197  *tP++ = (unsigned char)(255 * PPM_GETG(row_data[col]) / _maxval);
1198  *tP++ = (unsigned char)(255 * PPM_GETB(row_data[col]) / _maxval);
1199  if (samplesperpixel==4) {
1200  *tP++ = (unsigned char)(255 * alpha_data[col] / _maxval);
1201  }
1202  }
1203  } else {
1204  tP = buf;
1205  for ( col = 0; col < _x_size; ++col ) {
1206  int s;
1207 
1208  s = ppm_lookupcolor( cht, (pixel *)(&row_data[col]) );
1209  if ( s == -1 ) {
1210  pnmimage_tiff_cat.error()
1211  << "Internal error: color not found?!? row=" << row
1212  << " col=" << col << "\n";
1213  return 0;
1214  }
1215  *tP++ = (unsigned char) s;
1216  if (samplesperpixel==2) {
1217  *tP++ = (unsigned char)(255 * alpha_data[col] / _maxval);
1218  }
1219  }
1220  }
1221  } else {
1222  xelval bigger_maxval;
1223  int bitshift;
1224  unsigned char byte;
1225  xelval s;
1226 
1227  bigger_maxval = pm_bitstomaxval( bitspersample );
1228  bitshift = 8 - bitspersample;
1229  byte = 0;
1230  tP = buf;
1231  for ( col = 0; col < _x_size; ++col ) {
1232  s = PPM_GETB(row_data[col]);
1233  if ( _maxval != bigger_maxval )
1234  s = (xelval)((long) s * bigger_maxval / _maxval);
1235  byte |= s << bitshift;
1236  bitshift -= bitspersample;
1237  if ( bitshift < 0 ) {
1238  *tP++ = byte;
1239  bitshift = 8 - bitspersample;
1240  byte = 0;
1241  }
1242  }
1243  if ( bitshift != 8 - bitspersample )
1244  *tP++ = byte;
1245  }
1246 
1247  if ( TIFFWriteScanline( tif, buf, row, 0 ) < 0 ) {
1248  pnmimage_tiff_cat.error()
1249  << "failed a scanline write on row " << row << "\n";
1250  return row;
1251  }
1252  }
1253  TIFFFlushData( tif );
1254  TIFFClose( tif );
1255 
1256  return _y_size;
1257 }
1258 
1259 ////////////////////////////////////////////////////////////////////
1260 // Function: PNMFileTypeTIFF::install_error_handlers
1261 // Access: Private
1262 // Description: Installs our personal error and warning message
1263 // handlers if they have not already been installed.
1264 // These methods are used to route the Tiff error
1265 // messages through notify, so we can turn some of them
1266 // off.
1267 ////////////////////////////////////////////////////////////////////
1268 void PNMFileTypeTIFF::
1269 install_error_handlers() {
1270  if (!_installed_error_handlers) {
1271  TIFFSetWarningHandler(tiff_warning);
1272  TIFFSetErrorHandler(tiff_error);
1273  _installed_error_handlers = true;
1274  }
1275 }
1276 
1277 ////////////////////////////////////////////////////////////////////
1278 // Function: PNMFileTypeTIFF::tiff_warning
1279 // Access: Private, Static
1280 // Description: This is our own warning handler. It is called by the
1281 // tiff library to issue a warning message.
1282 ////////////////////////////////////////////////////////////////////
1283 void PNMFileTypeTIFF::
1284 tiff_warning(const char *, const char *format, va_list ap) {
1285  static const int buffer_size = 1024;
1286  char buffer[buffer_size];
1287 #if defined(WIN32_VC) || defined(WIN64_VC)
1288  vsprintf(buffer, format, ap);
1289 #else
1290  vsnprintf(buffer, buffer_size, format, ap);
1291 #endif
1292 
1293  // We ignore the module. It seems generally useless to us.
1294  pnmimage_tiff_cat.warning()
1295  << buffer << "\n";
1296 }
1297 
1298 ////////////////////////////////////////////////////////////////////
1299 // Function: PNMFileTypeTIFF::tiff_error
1300 // Access: Private, Static
1301 // Description: This is our own error handler. It is called by the
1302 // tiff library to issue a error message.
1303 ////////////////////////////////////////////////////////////////////
1304 void PNMFileTypeTIFF::
1305 tiff_error(const char *module, const char *format, va_list ap) {
1306  static const int buffer_size = 1024;
1307  char buffer[buffer_size];
1308 #if defined(WIN32_VC) || defined(WIN64_VC)
1309  vsprintf(buffer, format, ap);
1310 #else
1311  vsnprintf(buffer, buffer_size, format, ap);
1312 #endif
1313 
1314  // We ignore the module. It seems generally useless to us.
1315  pnmimage_tiff_cat.error()
1316  << buffer << "\n";
1317 }
1318 
1319 
1320 ////////////////////////////////////////////////////////////////////
1321 // Function: PNMFileTypeTIFF::register_with_read_factory
1322 // Access: Public, Static
1323 // Description: Registers the current object as something that can be
1324 // read from a Bam file.
1325 ////////////////////////////////////////////////////////////////////
1326 void PNMFileTypeTIFF::
1327 register_with_read_factory() {
1329  register_factory(get_class_type(), make_PNMFileTypeTIFF);
1330 }
1331 
1332 ////////////////////////////////////////////////////////////////////
1333 // Function: PNMFileTypeTIFF::make_PNMFileTypeTIFF
1334 // Access: Protected, Static
1335 // Description: This method is called by the BamReader when an object
1336 // of this type is encountered in a Bam file; it should
1337 // allocate and return a new object with all the data
1338 // read.
1339 //
1340 // In the case of the PNMFileType objects, since these
1341 // objects are all shared, we just pull the object from
1342 // the registry.
1343 ////////////////////////////////////////////////////////////////////
1344 TypedWritable *PNMFileTypeTIFF::
1345 make_PNMFileTypeTIFF(const FactoryParams &params) {
1346  return PNMFileTypeRegistry::get_global_ptr()->get_type_by_handle(get_class_type());
1347 }
1348 
1349 #endif // HAVE_TIFF
PNMFileType * get_type_by_handle(TypeHandle handle) const
Returns the PNMFileType instance stored in the registry for the given TypeHandle, e...
int get_num_channels() const
Returns the number of channels in the image.
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
int get_x_size() const
Returns the number of pixels in the X direction.
static void consider_yield()
Possibly suspends the current thread for the rest of the current epoch, if it has run for enough this...
Definition: thread.I:263
int get_y_size() const
Returns the number of pixels in the Y direction.
static PNMFileTypeRegistry * get_global_ptr()
Returns a pointer to the global PNMFileTypeRegistry object.
void swap_table(vector_float &table)
This is a very low-level function that completely exchanges the PfmFile&#39;s internal table of floating-...
Definition: pfmFile.I:619
Defines a pfm file, a 2-d table of floating-point numbers, either 3-component or 1-component, or with a special extension, 2- or 4-component.
Definition: pfmFile.h:34
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:40
bool has_alpha() const
Returns true if the image includes an alpha channel, false otherwise.
This is an abstract base class that defines the interface for reading image files of various types...
Definition: pnmReader.h:31
bool is_grayscale() const
Returns false if the image is a full-color image, and has red, green, and blue components; true if it...
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
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
void clear()
Eliminates all data in the file.
Definition: pfmFile.cxx:81