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