Panda3D
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 = min(8, 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 = min(8, pm_maxvaltobits(_maxval));
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
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 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.
int get_x_size() const
Returns the number of pixels in the X direction.
static PNMFileTypeRegistry * get_global_ptr()
Returns a pointer to the global PNMFileTypeRegistry object.
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
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
bool has_alpha() const
Returns true if the image includes an alpha channel, false otherwise.
int get_num_channels() const
Returns the number of channels in the image.
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
bool is_grayscale() const
Returns false if the image is a full-color image, and has red, green, and blue components; true if it...
void clear()
Eliminates all data in the file.
Definition: pfmFile.cxx:81